From 07906025141cbd7103b8a85620f82a237877402b Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Sat, 11 Jan 2020 04:16:31 +0000 Subject: [PATCH 01/16] nix: revamp the hierarchy --- .envrc | 6 +- .gitignore | 1 + .gitmodules | 3 - .lib/nixpkgs-sourcephile | 1 - Makefile | 19 +- bootstrap/mermet/etc/dropbear/.gitignore | 1 - "bootstrap/s\303\251vy/configuration.nix" | 128 ---- "bootstrap/s\303\251vy/hardware.nix" | 76 -- "bootstrap/s\303\251vy/system.nix" | 204 ----- build/modules.nix | 12 - build/modules/nix-plugins.nix | 8 - install/logical.nix | 14 - install/logical/friot.nix | 325 -------- install/logical/friot/discourse.nix | 147 ---- install/logical/friot/dovecot.nix | 641 ---------------- install/logical/friot/dovecot/autoconfig.nix | 69 -- install/logical/friot/gitolite.nix | 80 -- install/logical/friot/nginx.nix | 180 ----- install/logical/friot/nginx/gitweb.nix | 111 --- install/logical/friot/nsd.nix | 26 - install/logical/friot/nsd/sourcephile.nix | 98 --- install/logical/friot/openldap.nix | 171 ----- install/logical/friot/openldap/plurasoft.nix | 150 ---- .../friot/openldap/schema/postfix-book.ldif | 73 -- install/logical/friot/postfix.nix | 475 ------------ install/logical/friot/postgresql.nix | 236 ------ install/logical/friot/postgrey.nix | 14 - install/logical/friot/redmine.nix | 212 ------ install/logical/friot/rmilter.nix | 93 --- install/logical/friot/rspamd.nix | 221 ------ install/logical/friot/shorewall.nix | 148 ---- install/logical/machines.list | 18 - install/logical/mermet.nix | 15 - install/mermet/configuration.nix | 8 - install/mermet/logical.nix | 8 - install/mermet/logical/boot.nix | 5 - install/mermet/logical/networking.nix | 6 - install/mermet/physical.nix | 2 - install/overlays.nix | 11 - .../redmine/redmine_git_hosting.nix | 34 - .../overlays/servers/mail/rspamd/service.nix | 421 ----------- .../overlays/tools/networking/shorewall.nix | 3 - .../overlays/tools/networking/shorewall6.nix | 3 - .../tools/networking/shorewall6/service.nix | 75 -- install/overlays/users-init.nix | 8 - install/physical.nix | 2 - install/physical/production.nix | 30 - install/physical/staging.nix | 49 -- network.nix | 13 + network/mermet.nix | 7 + {install => network}/mermet/Makefile | 17 +- network/mermet/configuration.nix | 14 + network/mermet/deployment/lab.nix | 3 + network/mermet/deployment/production.nix | 3 + .../mermet/deployment/staging.nix | 0 {install => network}/mermet/hosting.nix | 0 {install => network}/mermet/hosting/lab.nix | 0 {install => network}/mermet/hosting/ptt.nix | 0 network/mermet/machine.nix | 2 + .../mermet/machine}/apu2e4.nix | 5 +- .../mermet/machine/apu2e4}/sfdisk.txt | 0 network/mermet/system.nix | 42 ++ .../logical => network/mermet/system}/zfs.nix | 1 + .../logical/system.nix => nixos/defaults.nix | 50 +- .../etc => nixos/defaults/readline}/inputrc | 0 nixos/modules.nix | 32 + nixos/modules/services/mail/dovecot.nix | 710 ++++++++++++++++++ .../modules/services/networking/domains.nix | 13 +- .../modules/services/networking/shorewall.nix | 2 + nixos/modules/services/security/x509.nix | 261 +++++++ overlays.nix | 11 + overlays/lib/filesystem.nix | 18 + .../overlays => overlays}/lib/strings.nix | 0 .../servers/mail/dovecot.nix | 0 .../servers/mail/postfix.nix | 0 .../tools/networking/shorewall/default.nix | 0 shell.nix | 21 +- shell => shell.sh | 0 shell/configuration.nix | 8 + .../modules => shell/configuration}/gnupg.nix | 6 +- shell/modules.nix | 40 + .../development/libraries/nix-plugins.nix | 95 +++ shell/modules/tools/security/gnupg.nix | 481 ++++++++++++ .../tools/security/gnupg/keyserver.pem | 57 ++ 84 files changed, 1876 insertions(+), 4677 deletions(-) delete mode 160000 .lib/nixpkgs-sourcephile delete mode 100644 bootstrap/mermet/etc/dropbear/.gitignore delete mode 100644 "bootstrap/s\303\251vy/configuration.nix" delete mode 100644 "bootstrap/s\303\251vy/hardware.nix" delete mode 100644 "bootstrap/s\303\251vy/system.nix" delete mode 100644 build/modules.nix delete mode 100644 build/modules/nix-plugins.nix delete mode 100644 install/logical.nix delete mode 100644 install/logical/friot.nix delete mode 100644 install/logical/friot/discourse.nix delete mode 100644 install/logical/friot/dovecot.nix delete mode 100644 install/logical/friot/dovecot/autoconfig.nix delete mode 100644 install/logical/friot/gitolite.nix delete mode 100644 install/logical/friot/nginx.nix delete mode 100644 install/logical/friot/nginx/gitweb.nix delete mode 100644 install/logical/friot/nsd.nix delete mode 100644 install/logical/friot/nsd/sourcephile.nix delete mode 100644 install/logical/friot/openldap.nix delete mode 100644 install/logical/friot/openldap/plurasoft.nix delete mode 100644 install/logical/friot/openldap/schema/postfix-book.ldif delete mode 100644 install/logical/friot/postfix.nix delete mode 100644 install/logical/friot/postgresql.nix delete mode 100644 install/logical/friot/postgrey.nix delete mode 100644 install/logical/friot/redmine.nix delete mode 100644 install/logical/friot/rmilter.nix delete mode 100644 install/logical/friot/rspamd.nix delete mode 100644 install/logical/friot/shorewall.nix delete mode 100644 install/logical/machines.list delete mode 100644 install/logical/mermet.nix delete mode 100644 install/mermet/configuration.nix delete mode 100644 install/mermet/logical.nix delete mode 100644 install/mermet/logical/boot.nix delete mode 100644 install/mermet/logical/networking.nix delete mode 100644 install/mermet/physical.nix delete mode 100644 install/overlays.nix delete mode 100644 install/overlays/applications/version-management/redmine/redmine_git_hosting.nix delete mode 100644 install/overlays/servers/mail/rspamd/service.nix delete mode 100644 install/overlays/tools/networking/shorewall.nix delete mode 100644 install/overlays/tools/networking/shorewall6.nix delete mode 100644 install/overlays/tools/networking/shorewall6/service.nix delete mode 100644 install/overlays/users-init.nix delete mode 100644 install/physical.nix delete mode 100644 install/physical/production.nix delete mode 100644 install/physical/staging.nix create mode 100644 network.nix create mode 100644 network/mermet.nix rename {install => network}/mermet/Makefile (94%) create mode 100644 network/mermet/configuration.nix create mode 100644 network/mermet/deployment/lab.nix create mode 100644 network/mermet/deployment/production.nix rename install/mermet/physical/virtualbox.nix => network/mermet/deployment/staging.nix (100%) rename {install => network}/mermet/hosting.nix (100%) rename {install => network}/mermet/hosting/lab.nix (100%) rename {install => network}/mermet/hosting/ptt.nix (100%) create mode 100644 network/mermet/machine.nix rename {install/mermet/physical => network/mermet/machine}/apu2e4.nix (95%) rename {install/mermet/physical => network/mermet/machine/apu2e4}/sfdisk.txt (100%) create mode 100644 network/mermet/system.nix rename {install/mermet/logical => network/mermet/system}/zfs.nix (99%) rename install/mermet/logical/system.nix => nixos/defaults.nix (59%) rename {install/mermet/logical/etc => nixos/defaults/readline}/inputrc (100%) create mode 100644 nixos/modules.nix create mode 100644 nixos/modules/services/mail/dovecot.nix rename install/options.nix => nixos/modules/services/networking/domains.nix (80%) rename install/overlays/tools/networking/shorewall/service.nix => nixos/modules/services/networking/shorewall.nix (99%) create mode 100644 nixos/modules/services/security/x509.nix create mode 100644 overlays.nix create mode 100644 overlays/lib/filesystem.nix rename {install/overlays => overlays}/lib/strings.nix (100%) rename {install/overlays => overlays}/servers/mail/dovecot.nix (100%) rename {install/overlays => overlays}/servers/mail/postfix.nix (100%) rename {install/overlays => pkgs}/tools/networking/shorewall/default.nix (100%) rename shell => shell.sh (100%) create mode 100644 shell/configuration.nix rename {build/modules => shell/configuration}/gnupg.nix (76%) create mode 100644 shell/modules.nix create mode 100644 shell/modules/development/libraries/nix-plugins.nix create mode 100644 shell/modules/tools/security/gnupg.nix create mode 100644 shell/modules/tools/security/gnupg/keyserver.pem diff --git a/.envrc b/.envrc index 480333a..d7a6ca6 100644 --- 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 < - ]; - -# 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\303\251vy/system.nix" "b/bootstrap/s\303\251vy/system.nix" deleted file mode 100644 index 6a9d51f..0000000 --- "a/bootstrap/s\303\251vy/system.nix" +++ /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 index d0c3e6c..0000000 --- a/build/modules.nix +++ /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 index 9afbcf5..0000000 --- a/build/modules/nix-plugins.nix +++ /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 index def0af8..0000000 --- a/install/logical.nix +++ /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 index e121543..0000000 --- a/install/logical/friot.nix +++ /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 = [ - - ../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 index 2073346..0000000 --- a/install/logical/friot/discourse.nix +++ /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 index 3f80959..0000000 --- a/install/logical/friot/dovecot.nix +++ /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 < $out/bin/learn-ham.sh </, 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 = - - - - - %EMAILDOMAIN% - - mail.%EMAILDOMAIN% - 993 - SSL - %EMAILADDRESS% - password-cleartext - - - mail.%EMAILDOMAIN% - 995 - SSL - %EMAILADDRESS% - password-cleartext - - false - true - - - - mail.%EMAILDOMAIN% - 465 - SSL - %EMAILADDRESS% - password-cleartext - - true - false - - - - - ''; - }; - }; - }; -}; -} diff --git a/install/logical/friot/gitolite.nix b/install/logical/friot/gitolite.nix deleted file mode 100644 index 1992c3c..0000000 --- a/install/logical/friot/gitolite.nix +++ /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 index 01aa7a7..0000000 --- a/install/logical/friot/nginx.nix +++ /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 index f095779..0000000 --- a/install/logical/friot/nginx/gitweb.nix +++ /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 index 9aabb64..0000000 --- a/install/logical/friot/nsd.nix +++ /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 index f83a07f..0000000 --- a/install/logical/friot/nsd/sourcephile.nix +++ /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 index 79b8eda..0000000 --- a/install/logical/friot/openldap.nix +++ /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 index 9a13f28..0000000 --- a/install/logical/friot/openldap/plurasoft.nix +++ /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 index d61c582..0000000 --- a/install/logical/friot/openldap/schema/postfix-book.ldif +++ /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 index bf36337..0000000 --- a/install/logical/friot/postfix.nix +++ /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 index bc7e6f7..0000000 --- a/install/logical/friot/postgresql.nix +++ /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 - < - #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 index 0fded48..0000000 --- a/install/logical/friot/rmilter.nix +++ /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 index 9395db0..0000000 --- a/install/logical/friot/rspamd.nix +++ /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 index 0def4e8..0000000 --- a/install/logical/friot/shorewall.nix +++ /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 index 8a632c1..0000000 --- a/install/logical/machines.list +++ /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 index 6df6654..0000000 --- a/install/logical/mermet.nix +++ /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 = [ - - ../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 index 1c0b494..0000000 --- a/install/mermet/configuration.nix +++ /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 index 9f84450..0000000 --- a/install/mermet/logical.nix +++ /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 index 96c205b..0000000 --- a/install/mermet/logical/boot.nix +++ /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 index dcf53ce..0000000 --- a/install/mermet/logical/networking.nix +++ /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 index acea9dd..0000000 --- a/install/mermet/physical.nix +++ /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 index 7f1d9cd..0000000 --- a/install/overlays.nix +++ /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 index f0cac14..0000000 --- a/install/overlays/applications/version-management/redmine/redmine_git_hosting.nix +++ /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 index 481684e..0000000 --- a/install/overlays/servers/mail/rspamd/service.nix +++ /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 "warning: ${w}" 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 proxy is - deprecated and only kept for backwards compatibility and should be - replaced with rspamd_proxy. - ''; - 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 /etc/rspamd/local.d/{name}. - ''; - 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 /etc/rspamd/override.d/{name}. - ''; - 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 /etc/rspamd/rspamd.local.lua 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 index 8f655c8..0000000 --- a/install/overlays/tools/networking/shorewall.nix +++ /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 index a5000bc..0000000 --- a/install/overlays/tools/networking/shorewall6.nix +++ /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 index 9c22a03..0000000 --- a/install/overlays/tools/networking/shorewall6/service.nix +++ /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. - - - Enabling this service WILL disable the existing NixOS - firewall! Default firewall rules provided by packages are not - considered at the moment. - - - ''; - }; - 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 index 492ef78..0000000 --- a/install/overlays/users-init.nix +++ /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 index d6b0d45..0000000 --- a/install/physical.nix +++ /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 index 68731ab..0000000 --- a/install/physical/production.nix +++ /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 index 23ea068..0000000 --- a/install/physical/staging.nix +++ /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 index 0000000..b97e22a --- /dev/null +++ b/network.nix @@ -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 index 0000000..f13b008 --- /dev/null +++ b/network/mermet.nix @@ -0,0 +1,7 @@ +{pkgs, lib, config, ...}: +{ + imports = [ + mermet/configuration.nix + (builtins.toPath ./mermet + "/deployment/" + builtins.getEnv "NIXOPS_DEPLOYMENT" + ".nix") + ]; +} diff --git a/install/mermet/Makefile b/network/mermet/Makefile similarity index 94% rename from install/mermet/Makefile rename to network/mermet/Makefile index b9aa950..3ad3ddd 100644 --- a/install/mermet/Makefile +++ b/network/mermet/Makefile @@ -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) +# +# +# +# +# %EMAILDOMAIN% +# +# imap.%EMAILDOMAIN% +# 993 +# SSL +# %EMAILADDRESS% +# password-cleartext +# +# +# pop.%EMAILDOMAIN% +# 995 +# SSL +# %EMAILADDRESS% +# password-cleartext +# +# false +# true +# +# +# +# smtp.%EMAILDOMAIN% +# 465 +# SSL +# %EMAILADDRESS% +# password-cleartext +# +# true +# false +# +# +# +# +# ''; +# }; +# 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`. + # ''; + #}; + diff --git a/install/options.nix b/nixos/modules/services/networking/domains.nix similarity index 80% rename from install/options.nix rename to nixos/modules/services/networking/domains.nix index 5c6cfb7..664935d 100644 --- a/install/options.nix +++ b/nixos/modules/services/networking/domains.nix @@ -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 { diff --git a/install/overlays/tools/networking/shorewall/service.nix b/nixos/modules/services/networking/shorewall.nix similarity index 99% rename from install/overlays/tools/networking/shorewall/service.nix rename to nixos/modules/services/networking/shorewall.nix index 0f94d41..75d65bf 100644 --- a/install/overlays/tools/networking/shorewall/service.nix +++ b/nixos/modules/services/networking/shorewall.nix @@ -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 index 0000000..8e434b3 --- /dev/null +++ b/nixos/modules/services/security/x509.nix @@ -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 index 0000000..04e6e2a --- /dev/null +++ b/overlays.nix @@ -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 index 0000000..e155cf5 --- /dev/null +++ b/overlays/lib/filesystem.nix @@ -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); + }; +} diff --git a/install/overlays/lib/strings.nix b/overlays/lib/strings.nix similarity index 100% rename from install/overlays/lib/strings.nix rename to overlays/lib/strings.nix diff --git a/install/overlays/servers/mail/dovecot.nix b/overlays/servers/mail/dovecot.nix similarity index 100% rename from install/overlays/servers/mail/dovecot.nix rename to overlays/servers/mail/dovecot.nix diff --git a/install/overlays/servers/mail/postfix.nix b/overlays/servers/mail/postfix.nix similarity index 100% rename from install/overlays/servers/mail/postfix.nix rename to overlays/servers/mail/postfix.nix diff --git a/install/overlays/tools/networking/shorewall/default.nix b/pkgs/tools/networking/shorewall/default.nix similarity index 100% rename from install/overlays/tools/networking/shorewall/default.nix rename to pkgs/tools/networking/shorewall/default.nix diff --git a/shell.nix b/shell.nix index afb6ea5..0830b72 100644 --- 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 index 0000000..d8dacfd --- /dev/null +++ b/shell/configuration.nix @@ -0,0 +1,8 @@ +{config, ...}: +{ + imports = [ + configuration/gnupg.nix + ]; + config = { + }; +} diff --git a/build/modules/gnupg.nix b/shell/configuration/gnupg.nix similarity index 76% rename from build/modules/gnupg.nix rename to shell/configuration/gnupg.nix index 39833ae..4ae3c0e 100644 --- a/build/modules/gnupg.nix +++ b/shell/configuration/gnupg.nix @@ -5,12 +5,12 @@ enable = true; dir.var = toString ../../../sec/gnupg; keys = { - "Sourcephile " = { - uid = "Sourcephile "; + "Julien Moutinho " = { + uid = "Julien Moutinho "; 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 index 0000000..c838ffe --- /dev/null +++ b/shell/modules.nix @@ -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 index 0000000..3a1b182 --- /dev/null +++ b/shell/modules/development/libraries/nix-plugins.nix @@ -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 index 0000000..083e704 --- /dev/null +++ b/shell/modules/tools/security/gnupg.nix @@ -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 &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. " = { + 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 "; + 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 index 0000000..d71be86 --- /dev/null +++ b/shell/modules/tools/security/gnupg/keyserver.pem @@ -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----- -- 2.44.1 From aa21a9ccb0806eadbb1423f357a360f7fb8f0825 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Sat, 11 Jan 2020 23:14:10 +0000 Subject: [PATCH 02/16] nix: revamp the hierarchy (again) --- .lib/nixops/Makefile.make | 2 +- Makefile | 19 +------- network/mermet.nix | 7 --- network/mermet/configuration.nix | 14 ------ network/mermet/deployment/lab.nix | 3 -- network/mermet/deployment/production.nix | 3 -- network/mermet/hosting.nix | 2 - network/mermet/machine.nix | 2 - network/mermet/system.nix | 42 ----------------- pkgs/installer/nixops-virtualbox/default.nix | 35 ++++++++++++++ .../machine-configuration-nixops.nix | 46 +++++++++++++++++++ network.nix => servers.nix | 0 servers/mermet.nix | 31 +++++++++++++ {network => servers}/mermet/Makefile | 16 +++---- .../lab.nix => servers/mermet/hosting/lan.nix | 0 .../mermet/hosting/localhost.nix | 18 ++------ {network => servers}/mermet/hosting/ptt.nix | 5 +- .../mermet/machine/apu2e4.nix | 0 .../mermet/machine}/sfdisk.txt | 0 servers/mermet/machine/virtualbox.nix | 14 ++++++ servers/mermet/system.nix | 43 +++++++++++++++++ {network => servers}/mermet/system/zfs.nix | 0 shell/configuration/gnupg.nix | 2 +- 23 files changed, 188 insertions(+), 116 deletions(-) delete mode 100644 network/mermet.nix delete mode 100644 network/mermet/configuration.nix delete mode 100644 network/mermet/deployment/lab.nix delete mode 100644 network/mermet/deployment/production.nix delete mode 100644 network/mermet/hosting.nix delete mode 100644 network/mermet/machine.nix delete mode 100644 network/mermet/system.nix create mode 100644 pkgs/installer/nixops-virtualbox/default.nix create mode 100644 pkgs/installer/nixops-virtualbox/machine-configuration-nixops.nix rename network.nix => servers.nix (100%) create mode 100644 servers/mermet.nix rename {network => servers}/mermet/Makefile (94%) rename network/mermet/hosting/lab.nix => servers/mermet/hosting/lan.nix (100%) rename network/mermet/deployment/staging.nix => servers/mermet/hosting/localhost.nix (55%) rename {network => servers}/mermet/hosting/ptt.nix (53%) rename {network => servers}/mermet/machine/apu2e4.nix (100%) rename {network/mermet/machine/apu2e4 => servers/mermet/machine}/sfdisk.txt (100%) create mode 100644 servers/mermet/machine/virtualbox.nix create mode 100644 servers/mermet/system.nix rename {network => servers}/mermet/system/zfs.nix (100%) diff --git a/.lib/nixops/Makefile.make b/.lib/nixops/Makefile.make index 86c79d6..a04ec81 100644 --- a/.lib/nixops/Makefile.make +++ b/.lib/nixops/Makefile.make @@ -9,7 +9,7 @@ $(dir $(NIXOPS_STATE))/virtualbox/nixops.vmdk: time nix $(NIX_FLAGS) build \ --out-link .cache/nixops/virtualbox \ --argstr system x86_64-linux \ - -f "" + -f "" # ## create diff --git a/Makefile b/Makefile index 2e25aa7..4681f18 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: init include .lib/nix/Makefile.make include .lib/nixops/Makefile.make -include machines/mermet/Makefile +include servers/mermet/Makefile # ## init @@ -16,20 +16,3 @@ 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/network/mermet.nix b/network/mermet.nix deleted file mode 100644 index f13b008..0000000 --- a/network/mermet.nix +++ /dev/null @@ -1,7 +0,0 @@ -{pkgs, lib, config, ...}: -{ - imports = [ - mermet/configuration.nix - (builtins.toPath ./mermet + "/deployment/" + builtins.getEnv "NIXOPS_DEPLOYMENT" + ".nix") - ]; -} diff --git a/network/mermet/configuration.nix b/network/mermet/configuration.nix deleted file mode 100644 index db430c8..0000000 --- a/network/mermet/configuration.nix +++ /dev/null @@ -1,14 +0,0 @@ -# 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 deleted file mode 100644 index 6e6bdbe..0000000 --- a/network/mermet/deployment/lab.nix +++ /dev/null @@ -1,3 +0,0 @@ -{pkgs, lib, config, ...}: { - deployment.targetHost = "mermet"; -} diff --git a/network/mermet/deployment/production.nix b/network/mermet/deployment/production.nix deleted file mode 100644 index e83d139..0000000 --- a/network/mermet/deployment/production.nix +++ /dev/null @@ -1,3 +0,0 @@ -{pkgs, lib, config, ...}: { - deployment.targetHost = "1.2.3.4"; -} diff --git a/network/mermet/hosting.nix b/network/mermet/hosting.nix deleted file mode 100644 index d80cb10..0000000 --- a/network/mermet/hosting.nix +++ /dev/null @@ -1,2 +0,0 @@ -with builtins; -import (toPath ./. + "/hosting/" + getEnv "MERMET_HOSTING" + ".nix") diff --git a/network/mermet/machine.nix b/network/mermet/machine.nix deleted file mode 100644 index 7705bd3..0000000 --- a/network/mermet/machine.nix +++ /dev/null @@ -1,2 +0,0 @@ -with builtins; -import (toPath ./. + "/machine/" + getEnv "MERMET_MACHINE" + ".nix") diff --git a/network/mermet/system.nix b/network/mermet/system.nix deleted file mode 100644 index a24b851..0000000 --- a/network/mermet/system.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ 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 - ]; - }; -} diff --git a/pkgs/installer/nixops-virtualbox/default.nix b/pkgs/installer/nixops-virtualbox/default.nix new file mode 100644 index 0000000..0f19125 --- /dev/null +++ b/pkgs/installer/nixops-virtualbox/default.nix @@ -0,0 +1,35 @@ +{ nixos ? +, system ? builtins.currentSystem +}: + +let + + machine-configuration = import ./machine-configuration-nixops.nix; + + machine = import nixos { + inherit system; + configuration = machine-configuration; + }; + + # TODO: Not yet sure if using the local packages is the best approach + pkgs = import { }; + +in rec { + + ova = machine.config.system.build.virtualBoxOVA; + + nixos-disk = pkgs.stdenv.mkDerivation rec { + name = "nixops-${version}.vmdk"; + version = machine.config.system.nixos.release; + phases = [ "installPhase" ]; + nativeBuildInputs = [ ova ]; + installPhase = '' + mkdir ova + tar -xf ${ova}/*.ova -C ova + mkdir -p $out + mv ova/nixos*.vmdk $out/nixops-${version}.vmdk + ln -s nixops-${version}.vmdk $out/nixops.vmdk + ''; + }; + +} diff --git a/pkgs/installer/nixops-virtualbox/machine-configuration-nixops.nix b/pkgs/installer/nixops-virtualbox/machine-configuration-nixops.nix new file mode 100644 index 0000000..bb0fd08 --- /dev/null +++ b/pkgs/installer/nixops-virtualbox/machine-configuration-nixops.nix @@ -0,0 +1,46 @@ +{ config, ... }: + +let + + clientKeyPath = "/root/.vbox-nixops-client-key"; + +in { + + imports = [ ]; + + services.openssh.enable = true; + + systemd.services.get-vbox-nixops-client-key = { + description = "Get NixOps SSH Key"; + wantedBy = [ "multi-user.target" ]; + before = [ "sshd.service" ]; + requires = [ "dev-vboxguest.device" ]; + after = [ "dev-vboxguest.device" ]; + path = [ config.boot.kernelPackages.virtualboxGuestAdditions ]; + script = '' + set -o pipefail + VBoxControl -nologo guestproperty get /VirtualBox/GuestInfo/Charon/ClientPublicKey | sed 's/Value: //' > ${clientKeyPath}.tmp + mv ${clientKeyPath}.tmp ${clientKeyPath} + + if [[ ! -f /etc/ssh/ssh_host_ed25519_key ]]; then + VBoxControl -nologo guestproperty get /VirtualBox/GuestInfo/NixOps/PrivateHostEd25519Key | sed 's/Value: //' > /etc/ssh/ssh_host_ed25519_key.tmp + mv /etc/ssh/ssh_host_ed25519_key.tmp /etc/ssh/ssh_host_ed25519_key + chmod 0600 /etc/ssh/ssh_host_ed25519_key + fi + ''; + }; + + services.openssh.authorizedKeysFiles = [ ".vbox-nixops-client-key" ]; + + boot.vesa = false; + + boot.loader.timeout = 1; + + # VirtualBox doesn't seem to lease IP addresses persistently, so we + # may get a different IP address if dhcpcd is restarted. So don't + # restart dhcpcd. + systemd.services.dhcpcd.restartIfChanged = false; + + # Useless there and CPU intensive. + documentation.nixos.enable = false; +} diff --git a/network.nix b/servers.nix similarity index 100% rename from network.nix rename to servers.nix diff --git a/servers/mermet.nix b/servers/mermet.nix new file mode 100644 index 0000000..eaa2476 --- /dev/null +++ b/servers/mermet.nix @@ -0,0 +1,31 @@ +# 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 machine, +# only the resulting closure is copied to the target machine. +{pkgs, lib, config, options, nodes, resources, ...}: +let + deployment = builtins.getAttr + (lib.maybeEnv "NIXOPS_DEPLOYMENT" "production") + deployments; + deployments = { + maintenance = [ + mermet/machine/apu2e4.nix + mermet/hosting/lan.nix + ]; + production = [ + mermet/machine/apu2e4.nix + mermet/hosting/ptt.nix + ]; + staging = [ + mermet/machine/virtualbox.nix + mermet/hosting/localhost.nix + ]; + }; +in +{ + nixpkgs.overlays = import ../overlays.nix; + imports = + [ ../nixos/defaults.nix + mermet/system.nix + ] ++ deployment; +} diff --git a/network/mermet/Makefile b/servers/mermet/Makefile similarity index 94% rename from network/mermet/Makefile rename to servers/mermet/Makefile index 3ad3ddd..98c5225 100644 --- a/network/mermet/Makefile +++ b/servers/mermet/Makefile @@ -1,7 +1,6 @@ #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) +NIXOPS_DEPLOYMENT := maintenance +mermet_disk := $(shell sed -ne 's/^device: \(.*\)/\1/p' machine/sfdisk.txt) mermet_cipher := #mermet_cipher := aes-128-gcm mermet_autotrim := @@ -18,7 +17,7 @@ mermet-wipeout: mermet-umount mermet-partition: sudo modprobe zfs - sudo $$(which sfdisk) $(mermet_disk) Date: Sun, 12 Jan 2020 08:57:16 +0000 Subject: [PATCH 03/16] nix: add predictable interface names --- nixos/defaults.nix | 1 + .../defaults/predictable-interface-names.nix | 79 ++++++++++++++++ servers.nix | 6 +- servers/mermet/Makefile | 29 +++--- servers/mermet/hosting/lan.nix | 4 +- servers/mermet/hosting/ptt.nix | 4 +- servers/mermet/machine/apu2e4.nix | 92 +++++++++++-------- 7 files changed, 155 insertions(+), 60 deletions(-) create mode 100644 nixos/defaults/predictable-interface-names.nix diff --git a/nixos/defaults.nix b/nixos/defaults.nix index a109da4..30ab620 100644 --- a/nixos/defaults.nix +++ b/nixos/defaults.nix @@ -2,6 +2,7 @@ { imports = [ ./modules.nix + ./defaults/predictable-interface-names.nix ]; config = { nix = { diff --git a/nixos/defaults/predictable-interface-names.nix b/nixos/defaults/predictable-interface-names.nix new file mode 100644 index 0000000..319d1a3 --- /dev/null +++ b/nixos/defaults/predictable-interface-names.nix @@ -0,0 +1,79 @@ +# Use predictable interface names in stage-1 and stage-2. +# DOC: https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/ +# +# Tip: names that can be given using ID_NET_NAME_* envvars +# can be checked before hand with: +# udevadm test-builtin net_id /sys/class/net/* + +{ pkgs, lib, config, ... }: +let udevNetSetupLinkRules = pkgs.writeTextFile { + name = "80-net-setup-link.rules"; + destination = "/etc/udev/rules.d/80-net-setup-link.rules"; + text = '' + SUBSYSTEM!="net", GOTO="net_setup_link_end" + + IMPORT{builtin}="path_id" + + ACTION!="add", GOTO="net_setup_link_end" + + # Load net_setup_link to setup the ID_NET_NAME_* envvars + IMPORT{builtin}="net_setup_link" + + # Rename eth* using the "path" name policy (eg. enp1s0), + # Note that in stage-1 the envvar ID_NET_NAME is not set, + # hence not usable as in $${pkgs.systemd}/lib/udev/rules.d/80-net-setup-link.rules + # Because in stage-1 there is no /etc/systemd/network/*.link + # nor **/systemd/network/99-default.link + # to set NamePolicy= which is responsible to set ID_NET_NAME. + # Not sure if ATTR{type}=="1" and KERNEL=="eth*" are equivalent or not. + ATTR{type}=="1", KERNEL=="eth*", NAME="$env{ID_NET_NAME_PATH}" + + LABEL="net_setup_link_end" + ''; + }; +in +{ + networking = { + # Currently no-op. + # false would set boot.kernelParams = [ "net.ifnames=0" ]; + # to disable NamePolicy= in *.link. + usePredictableInterfaceNames = true; + }; + + boot.initrd = { + extraUdevRulesCommands = '' + # Query hwdb to set some more ID_* in case someone need them for their rules. + cp -v ${pkgs.systemd}/lib/udev/rules.d/75-net-description.rules $out/ + + # The name set here in stage-1 by 80-net-setup-link.rules + # will stay in stage-2 (at least until the device is removed/added). + cp -v ${udevNetSetupLinkRules}/etc/udev/rules.d/80-net-setup-link.rules $out/ + ''; + }; + + services.udev.packages = [ + # Only useful here in stage-2 if the device is removed and re-added + # (eg. the network module is rmmod-ed then modprobe-d). + # The stage-1 (or initrd) is only a pivot_root after all, + # it does not reload the kernel, hence passing to stage-2 + # does not trigger ACTION=="add" for the net devices. + udevNetSetupLinkRules + ]; + + /* Useless block, only here for explanations. + + # NixOS put this .link only in the root filesystem, not in the initrd + # hence it's only active in stage-2, not stage-1. + # And even in stage-2, the 80-net-setup-link.rules has priority. + # DOC: https://www.freedesktop.org/software/systemd/man/systemd.link.html + environment.etc."systemd/network/79-net-setup.link".text = '' + [Match] + OriginalName=* + + [Link] + #NamePolicy=keep kernel database onboard slot path + NamePolicy=mac + MACAddressPolicy=persistent + ''; + */ +} diff --git a/servers.nix b/servers.nix index b97e22a..d31eb77 100644 --- a/servers.nix +++ b/servers.nix @@ -5,9 +5,9 @@ }; defaults = { - #imports = [ network/defaults.nix ]; + #imports = [ nixos/defaults.nix ]; }; - #friot = import network/friot.nix; - mermet = import network/mermet.nix; + #friot = import servers/friot.nix; + mermet = import servers/mermet.nix; } diff --git a/servers/mermet/Makefile b/servers/mermet/Makefile index 98c5225..1a6b4e9 100644 --- a/servers/mermet/Makefile +++ b/servers/mermet/Makefile @@ -1,8 +1,8 @@ #cwd := $(notdir $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))) NIXOPS_DEPLOYMENT := maintenance mermet_disk := $(shell sed -ne 's/^device: \(.*\)/\1/p' machine/sfdisk.txt) -mermet_cipher := -#mermet_cipher := aes-128-gcm +#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) @@ -10,18 +10,18 @@ mermet_reservation := 40G echo: echo $(MAKEFILES) -mermet-wipeout: mermet-umount +wipeout: umount sudo zpool labelclear -f $(mermet_disk)-part3 || true sudo zpool labelclear -f $(mermet_disk)-part5 || true sudo $$(which sgdisk) --zap-all $(mermet_disk) -mermet-partition: +partition: sudo modprobe zfs sudo $$(which sfdisk) $(mermet_disk) /dev/null || \ sudo zpool create -o ashift=12 \ @@ -140,7 +140,7 @@ mermet-format: sync=disabled \ rpool/var/tmp -mermet-mount: +mount: # scan needed zpools #sudo zpool list bpool || \ #sudo zpool import -f bpool @@ -183,8 +183,7 @@ mermet-mount: done sudo chmod 1777 /mnt/mermet/var/tmp -mermet-bootstrap: mermet-mount - sudo rm -rf /mnt/mermet/etc/nixos +bootstrap: mount #test "$$(sudo grub-probe /mnt/mermet/boot)" = zfs # NOTE: nixos-install will install GRUB following mermet.nix # BIOS @@ -197,10 +196,10 @@ mermet-bootstrap: mermet-mount # --recheck \ # --no-floppy - pass sourcephile/mermet/dropbear/host-ecdsa.key | \ + pass servers/mermet/dropbear/host.key | \ sudo install -D -o root -g root -m 400 /dev/stdin \ - /mnt/mermet/etc/dropbear/host-ecdsa.key && \ - test -s /mnt/mermet/etc/dropbear/host-ecdsa.key + /mnt/mermet/etc/dropbear/host.key && \ + test -s /mnt/mermet/etc/dropbear/host.key #trap "test ! -e SHRED-ME || sudo find SHRED-ME -type f -exec shred -u {} + && sudo rm -rf SHRED-ME" EXIT ; sudo \ @@ -221,7 +220,7 @@ mermet-bootstrap: mermet-mount --no-root-passwd \ --show-trace -mermet-umount: +umount: for p in \ boot/efi \ boot \ diff --git a/servers/mermet/hosting/lan.nix b/servers/mermet/hosting/lan.nix index 779b17e..894e9e7 100644 --- a/servers/mermet/hosting/lan.nix +++ b/servers/mermet/hosting/lan.nix @@ -2,7 +2,7 @@ { networking = { interfaces.enp1s0.useDHCP = true; - interfaces.enp2s0.useDHCP = true; - interfaces.enp3s0.useDHCP = true; + #interfaces.enp2s0.useDHCP = true; + #interfaces.enp3s0.useDHCP = true; }; } diff --git a/servers/mermet/hosting/ptt.nix b/servers/mermet/hosting/ptt.nix index d830365..21e42ee 100644 --- a/servers/mermet/hosting/ptt.nix +++ b/servers/mermet/hosting/ptt.nix @@ -2,8 +2,8 @@ { networking = { interfaces.enp1s0.useDHCP = true; - interfaces.enp2s0.useDHCP = true; - interfaces.enp3s0.useDHCP = true; + #interfaces.enp2s0.useDHCP = true; + #interfaces.enp3s0.useDHCP = true; }; } // lib.mkIf (builtins.hasAttr "mermet" nodes) { diff --git a/servers/mermet/machine/apu2e4.nix b/servers/mermet/machine/apu2e4.nix index 05e0905..4aa3b0c 100644 --- a/servers/mermet/machine/apu2e4.nix +++ b/servers/mermet/machine/apu2e4.nix @@ -8,6 +8,19 @@ in [ ]; + boot.kernel = { + sysctl = { + # Always reboot on a kernel panic, + # to not have to physically go power cycle the apu2e4. + # Which happens if the wrong ZFS password is used + # but the boot is manually forced to continue. + "kernel.panic" = 20; + + "vm.swappiness" = 10; + "vm.vfs_cache_pressure" = 50; + }; + }; + boot.loader = { grub = { enable = true; @@ -40,6 +53,8 @@ in "ehci_pci" "sd_mod" "uas" + # Ethernet driver + "igb" # Made the AES modules available at initrd, # to speedup the deciphering of the root. "aes_x86_64" @@ -47,6 +62,39 @@ in "cryptd" ]; kernelModules = [ ]; + network = { + # This will use udhcp to get an ip address. + # Make sure you have added the kernel module for your network driver to `boot.initrd.availableKernelModules`, + # so your initrd can load it! + # Static ip addresses might be configured using the ip argument in kernel command line: + # https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt + enable = true; + ssh = { + enable = true; + # To prevent ssh from freaking out because a different host key is used, + # a different port for dropbear is useful (assuming the same host has also a normal sshd running) + 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. + # Unfortunately pass cannot be used here because the key is not a valid Nix string. + 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" + ]; + }; + # this will automatically load the zfs password prompt on login + # and kill the other prompt so boot can continue + postCommands = '' + #zpool import rpool + #/bin/ash + echo "zfs load-key -a; killall zfs" >> /root/.profile + ''; + }; + }; boot.kernelModules = [ ]; boot.extraModulePackages = [ ]; @@ -57,44 +105,6 @@ in # DEBUG: "boot.shell_on_fail" "zfs.zfs_arc_max=262144000" # 250Mo ]; - boot.kernel = { - sysctl = { - "vm.swappiness" = 10; - "vm.vfs_cache_pressure" = 50; - }; - }; - - boot.initrd.network = { - # This will use udhcp to get an ip address. - # Make sure you have added the kernel module for your network driver to `boot.initrd.availableKernelModules`, - # so your initrd can load it! - # Static ip addresses might be configured using the ip argument in kernel command line: - # https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt - enable = true; - ssh = { - enable = true; - # To prevent ssh from freaking out because a different host key is used, - # a different port for dropbear is useful (assuming the same host has also a normal sshd running) - 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. - # Unfortunately pass cannot be used here because the key is not a valid Nix string. - 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" - ]; - }; - # this will automatically load the zfs password prompt on login - # and kill the other prompt so boot can continue - postCommands = '' - #zpool import rpool - echo "zfs load-key -a; killall zfs" >> /root/.profile - ''; - }; fileSystems."/boot" = { device = "/dev/disk/by-uuid/dc3c5387-17d2-43b3-bfa2-bf73afacca07"; @@ -118,4 +128,10 @@ in nix.maxJobs = lib.mkDefault 4; powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; + + environment = { + systemPackages = with pkgs; [ + pciutils + ]; + }; } -- 2.44.1 From ad8f0771e8811f8bcb981d3db316d8688e69c9e1 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Sun, 12 Jan 2020 12:58:05 +0000 Subject: [PATCH 04/16] mermet: install flashrom --- servers/mermet/machine/apu2e4.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/servers/mermet/machine/apu2e4.nix b/servers/mermet/machine/apu2e4.nix index 4aa3b0c..3aacd4f 100644 --- a/servers/mermet/machine/apu2e4.nix +++ b/servers/mermet/machine/apu2e4.nix @@ -132,6 +132,7 @@ in environment = { systemPackages = with pkgs; [ pciutils + flashrom ]; }; } -- 2.44.1 From 96f18a0163b7b880fda1d0e73acb92d6ca03d661 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Mon, 13 Jan 2020 05:17:41 +0000 Subject: [PATCH 05/16] nix: improve shell.nix's modules system --- shell.nix | 84 +++--- shell/configuration.nix | 8 - shell/configuration/gnupg.nix | 24 -- shell/gnupg/keys.nix | 15 ++ .../development/libraries/nix-plugins.nix | 133 ++++----- shell/modules/shells/nix-shell.nix | 21 ++ shell/modules/tools/networking/openssh.nix | 26 ++ .../modules/tools/package-management/nix.nix | 37 +++ shell/modules/tools/security/gnupg.nix | 254 +++++++++--------- 9 files changed, 311 insertions(+), 291 deletions(-) delete mode 100644 shell/configuration.nix delete mode 100644 shell/configuration/gnupg.nix create mode 100644 shell/gnupg/keys.nix create mode 100644 shell/modules/shells/nix-shell.nix create mode 100644 shell/modules/tools/networking/openssh.nix create mode 100644 shell/modules/tools/package-management/nix.nix diff --git a/shell.nix b/shell.nix index 0830b72..8d63df7 100644 --- a/shell.nix +++ b/shell.nix @@ -4,51 +4,47 @@ let config = {}; # Make the config pure, ignoring user's config. overlays = import ./overlays.nix; }; - # Using modules enables to separate specific configurations in shell/configuration.nix - # from reusable code in shell/modules.nix + nixos = pkgs.nixos {}; + + # Configuration of shell/modules/ + configuration = {config, ...}: { + imports = [ + ]; + nix-plugins = { + enable = true; + }; + gnupg = { + enable = true; + gnupgHome = toString ../sec/gnupg; + keys = import shell/gnupg/keys.nix; + }; + openssh = { + enable = true; + sshConf = '' + ''; + }; + }; + + # Using modules enables to separate specific configurations + # from reusable code in shell/modules.nix and shell/modules/ # which may find its way in another git repository one day. modules = (import shell/modules.nix { inherit pkgs; inherit (pkgs) lib; - modules = [ ( import shell/configuration.nix ) ]; + modules = [ configuration ]; }).config; - /* - sourcephile-nix-build = - pkgs.stdenv.mkDerivation { - name = "sourcephile-nix-build"; - preferLocalBuild = true; - allowSubstitutes = false; - inherit (pkgs) coreutils; - builder = pkgs.writeText "builder.sh" modules.init.builder; - }; - */ - sourcephile-nix-build = - pkgs.buildEnv { - name = "sourcephile-nix-build"; - pathsToLink = [ "/bin" ]; - paths = with modules; [ - gnupg.init - #gnupg.gpg-fingerprint - #nix-plugins.nix-with-extra-builtins - ]; - }; - nixos = pkgs.nixos {}; - nixos-generate-config = nixos.nixos-generate-config; - nixos-install = nixos.nixos-install; - nixos-enter = nixos.nixos-enter; in pkgs.stdenv.mkDerivation { name = "sourcephile-nix"; src = null; #preferLocalBuild = true; #allowSubstitutes = false; - buildInputs = [ - sourcephile-nix-build + buildInputs = modules.nix-shell.buildInputs ++ [ nixpkgs - nixos-generate-config - nixos-install - nixos-enter + nixos.nixos-generate-config + nixos.nixos-install + nixos.nixos-enter #pkgs.binutils pkgs.coreutils pkgs.cryptsetup @@ -97,8 +93,10 @@ pkgs.stdenv.mkDerivation { shellHook = '' echo >&2 "nix: running shellHook" + ${modules.nix-shell.shellHook} + # nix - export NIX_PATH="nixpkgs=${nixpkgs}:nixpkgs-sourcephile=$PWD/.lib/nixpkgs-sourcephile" + export NIX_PATH="nixpkgs=${nixpkgs}" NIX_PATH+=":nixpkgs-overlays="$PWD"/overlays" #NIX_PATH+="" @@ -108,15 +106,6 @@ pkgs.stdenv.mkDerivation { PATH_FHS="$PWD"/.lib/nix/fhs-bin PATH_FHS_VBOX="$PWD"/.lib/fhs-vbox-bin export PATH="$PATH_NIXOS:$PATH_FHS_VBOX:$PATH_FHS:$PATH:$PATH_NIX" - ln -sfn ${sourcephile-nix-build}/bin "$PWD"/.bin - - # nix.conf - export NIX_CONF_DIR="$PWD"/.config/nix - 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 = ${modules.nix-plugins.extra-builtins} - EOF # NOTE: sudo needs to be own by root with the setuid bit, # but this won't be the case for the sudo provided by Nix outside NixOS, @@ -129,20 +118,9 @@ pkgs.stdenv.mkDerivation { export LANG=fr_FR.UTF-8 export LC_CTYPE=fr_FR.UTF-8 - # gnupg - export GNUPGHOME="$PWD"/../sec/gnupg - install -dm700 "$GNUPGHOME" - export GPG_TTY=$(tty) - gpgconf --launch gpg-agent - export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) - # password-store export PASSWORD_STORE_DIR="$PWD"/../sec/pass - # openssl - export NIX_SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" - export SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" - # git gitdir="$PWD"/.git test ! -f "$gitdir" || while IFS=" :" read -r hdr gitdir; do [ "$hdr" != gitdir ] || break; done <"$gitdir" diff --git a/shell/configuration.nix b/shell/configuration.nix deleted file mode 100644 index d8dacfd..0000000 --- a/shell/configuration.nix +++ /dev/null @@ -1,8 +0,0 @@ -{config, ...}: -{ - imports = [ - configuration/gnupg.nix - ]; - config = { - }; -} diff --git a/shell/configuration/gnupg.nix b/shell/configuration/gnupg.nix deleted file mode 100644 index be5e798..0000000 --- a/shell/configuration/gnupg.nix +++ /dev/null @@ -1,24 +0,0 @@ -{config, ...}: -{ - config = { - gnupg = { - enable = true; - dir.var = toString ../../../sec/gnupg; - keys = { - "Julien Moutinho " = { - uid = "Julien Moutinho "; - algo = "rsa4096"; - expire = "3y"; - usage = ["cert" "sign"]; - passPath = "members/julm/gpg/password"; - subKeys = [ - { algo = "rsa4096"; expire = "3y"; usage = ["sign"];} - { algo = "rsa4096"; expire = "3y"; usage = ["encrypt"];} - { algo = "rsa4096"; expire = "3y"; usage = ["auth"];} - ]; - backupRecipients = [""]; - }; - }; - }; - }; -} diff --git a/shell/gnupg/keys.nix b/shell/gnupg/keys.nix new file mode 100644 index 0000000..91c22d9 --- /dev/null +++ b/shell/gnupg/keys.nix @@ -0,0 +1,15 @@ +{ + "Julien Moutinho " = { + uid = "Julien Moutinho "; + algo = "rsa4096"; + expire = "3y"; + usage = ["cert" "sign"]; + passPath = "members/julm/gpg/password"; + subKeys = [ + { algo = "rsa4096"; expire = "3y"; usage = ["sign"];} + { algo = "rsa4096"; expire = "3y"; usage = ["encrypt"];} + { algo = "rsa4096"; expire = "3y"; usage = ["auth"];} + ]; + backupRecipients = [""]; + }; +} diff --git a/shell/modules/development/libraries/nix-plugins.nix b/shell/modules/development/libraries/nix-plugins.nix index 3a1b182..a1a2798 100644 --- a/shell/modules/development/libraries/nix-plugins.nix +++ b/shell/modules/development/libraries/nix-plugins.nix @@ -1,17 +1,61 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.nix-plugins; + inherit (lib) types; + + # Wrapper around nix to load extra-builtins.nix with nix-plugins. + nix-with-extra-builtins = pkgs.writeShellScriptBin "nix-with-extra-builtins" '' + ${pkgs.nix}/bin/nix \ + --option plugin-files ${pkgs.nix-plugins}/lib/nix/plugins/libnix-extra-builtins.so \ + --option extra-builtins-file ${cfg.extra-builtins} \ + "$@" + ''; + + # 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 = pkgs.writeShellScriptBin "nix-pass" '' + 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:$:":;' + */ + + # 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-pass-to-file = pkgs.writeShellScriptBin "nix-pass-to-file" '' + set -e + set -o pipefail + ${pkgs.pass}/bin/pass show "$1" | + install -D -m 400 /dev/stdin "$2" + printf '%s\n' "$PWD/$2" + ''; + + # Wrapper around git to call it with exec in extra-builtins.nix. + nix-git = pkgs.writeShellScriptBin "nix-git" '' + cd "$1"; shift + ${pkgs.git}/bin/git "$@" + ''; in { options.nix-plugins = { enable = lib.mkEnableOption "nix-plugins"; - extra-builtins = mkOption { + extra-builtins = lib.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 ]; + pass = path: exec [ "${nix-pass}/bin/nix-pass" path ]; + pass-to-file = path: file: exec [ "${nix-pass-to-file}/bin/nix-pass-to-file" path file ]; + git = dir: args: exec ([ "${nix-git}/bin/nix-git" (builtins.toPath dir) ] ++ args); + git-time = dir: path: exec [ "${nix-git}/bin/nix-git" (builtins.toPath dir) "log" "-1" "--format=%ct" "--" path ]; ''; description = '' Content put in extra-builtins.nix for nix-plugins. @@ -21,75 +65,14 @@ in { '' + 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. - ''; + ''); }; }; + config = lib.mkIf cfg.enable { + nix.enable = true; + nix.nixConf = '' + plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins/libnix-extra-builtins.so + extra-builtins-file = ${cfg.extra-builtins} + ''; + }; } diff --git a/shell/modules/shells/nix-shell.nix b/shell/modules/shells/nix-shell.nix new file mode 100644 index 0000000..5ee6860 --- /dev/null +++ b/shell/modules/shells/nix-shell.nix @@ -0,0 +1,21 @@ +{ pkgs, lib, config, ... }: +let inherit (lib) types; +in +{ + options = { + nix-shell.buildInputs = lib.mkOption { + type = types.listOf types.package; + default = []; + description = '' + To be prepended to the shell.nix's buildInputs. + ''; + }; + nix-shell.shellHook = lib.mkOption { + type = types.lines; + default = ""; + description = '' + To be prepended to the shell.nix's shellHook. + ''; + }; + }; +} diff --git a/shell/modules/tools/networking/openssh.nix b/shell/modules/tools/networking/openssh.nix new file mode 100644 index 0000000..4322edc --- /dev/null +++ b/shell/modules/tools/networking/openssh.nix @@ -0,0 +1,26 @@ +{ pkgs, lib, config, ... }: +let cfg = config.openssh; + inherit (lib) types; +in +{ + options.openssh = { + enable = lib.mkEnableOption "OpenSSH shell utilities"; + sshConf = lib.mkOption { + type = types.lines; + apply = s: pkgs.writeText "ssh_config" s; + default = '' + ''; + description = '' + OpenSSH's ssh_config content. + ''; + }; + }; + config = lib.mkIf cfg.enable { + nix-shell.buildInputs = + let ssh = pkgs.writeShellScriptBin "ssh" '' + ${pkgs.openssh}/bin/ssh -F ${cfg.sshConf} "$@" + ''; + in + [ ssh ]; + }; +} diff --git a/shell/modules/tools/package-management/nix.nix b/shell/modules/tools/package-management/nix.nix new file mode 100644 index 0000000..88c0da6 --- /dev/null +++ b/shell/modules/tools/package-management/nix.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, ... }: +let cfg = config.nix; + inherit (lib) types; + /* Alternative which does not need to re-export envvars when called via sudo. + But this is maybe more clear to just (re-)export envvars. + nix = pkgs.writeShellScriptBin "nix" '' + NIX_CONF_DIR=${cfg.nixConf} \ + NIX_SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" \ + SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" \ + ${pkgs.nix}/bin/nix "$@" + ''; + */ +in +{ + options.nix = { + enable = lib.mkEnableOption "nix"; + nixConf = lib.mkOption { + type = types.lines; + apply = s: pkgs.writeText "nix.conf" s; + default = '' + auto-optimise-store = true + ''; + description = '' + Nix's nix.conf content. + ''; + }; + }; + config = lib.mkIf cfg.enable { + #shell.buildInputs = [ nix ]; + nix-shell.shellHook = '' + # nix + export NIX_CONF_DIR=${cfg.nixConf} + export NIX_SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + export SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + ''; + }; +} diff --git a/shell/modules/tools/security/gnupg.nix b/shell/modules/tools/security/gnupg.nix index 083e704..c582ec0 100644 --- a/shell/modules/tools/security/gnupg.nix +++ b/shell/modules/tools/security/gnupg.nix @@ -17,16 +17,16 @@ let cfg = config.gnupg; }@primary: '' info " generateKey uid=\"${uid}\"" - if ! ${cfg.gpg-with-home}/bin/gpg-with-home --list-secret-keys -- "=${uid}" >/dev/null 2>/dev/null + if ! ${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 \ + ${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 \ + fpr=$(${gpg-fingerprint}/bin/gpg-fingerprint -- "=${uid}" | head1) + caps=$(${gpg-with-home}/bin/gpg-with-home \ --with-colons --fixed-list-mode --with-fingerprint \ --list-secret-keys -- "=${uid}" | ${pkgs.gnugrep}/bin/grep '^ssb:' | @@ -47,7 +47,7 @@ let cfg = config.gnupg; 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 \ + ${gpg-with-home}/bin/gpg-with-home \ --batch --pinentry-mode loopback --passphrase-fd 0 \ --quick-add-key "$fpr" "${algo}" "${unwords usage}" "${expire}" fi @@ -62,72 +62,72 @@ let cfg = config.gnupg; 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" + mkdir -p "${cfg.gnupgHome}/backup/${uid}/" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.pubkey.asc" then - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${gpg-with-home}/bin/gpg-with-home \ --batch \ - --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.pubkey.asc" \ + --armor --yes --output "${cfg.gnupgHome}/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" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc" then ${pkgs.pass}/bin/pass "${passPath}" | - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${gpg-with-home}/bin/gpg-with-home \ --pinentry-mode loopback --passphrase-fd 0 \ - --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.revoke.asc" \ + --armor --yes --output "${cfg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc" \ --gen-revoke "${fpr}" fi - if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.privkey.sec" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.privkey.sec" then ${pkgs.pass}/bin/pass "${passPath}" | - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${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" \ + --armor --yes --output "${cfg.gnupgHome}/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" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.subkeys.sec" then ${pkgs.pass}/bin/pass "${passPath}" | - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${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" \ + --armor --yes --output "${cfg.gnupgHome}/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" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc.gpg" then ${pkgs.pass}/bin/pass "${passPath}" | - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${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" + --armor --yes --output "${cfg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc.gpg" fi - if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.privkey.sec.gpg" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.privkey.sec.gpg" then ${pkgs.pass}/bin/pass "${passPath}" | - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${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" + --armor --yes --output "${cfg.gnupgHome}/backup/${uid}/${fpr}.privkey.sec.gpg" fi - if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.subkeys.sec.gpg" + if ! test -s "${cfg.gnupgHome}/backup/${uid}/${fpr}.subkeys.sec.gpg" then ${pkgs.pass}/bin/pass "${passPath}" | - ${cfg.gpg-with-home}/bin/gpg-with-home \ + ${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" + --armor --yes --output "${cfg.gnupgHome}/backup/${uid}/${fpr}.subkeys.sec.gpg" fi ''); recipients = rs: unwords (map (r: ''--recipient "${refKey r}"'') rs); @@ -147,7 +147,7 @@ let cfg = config.gnupg; # to its password file. '' # shell.gnupg.pass.passOfFingerprint - for fpr in $(${cfg.gpg-fingerprint}/bin/gpg-fingerprint -- "=${key.uid}") + for fpr in $(${gpg-fingerprint}/bin/gpg-fingerprint -- "=${key.uid}") do eval "pass_$fpr=\"${key.passPath}\"" done ''; @@ -163,7 +163,7 @@ let cfg = config.gnupg; for keygrip in $keygrips do echo >&2 "gpg: forget: keygrip=$keygrip" - GNUPGHOME=${cfg.dir.var} \ + GNUPGHOME=${cfg.gnupgHome} \ ${pkgs.gnupg}/bin/gpg-connect-agent &2 "CLEAR_PASSPHRASE $keygrip" || true done @@ -178,10 +178,10 @@ let cfg = config.gnupg; '' ${unlines (map passOfFingerprint keys)} # presetPass - GNUPGHOME=${cfg.dir.var} \ + GNUPGHOME=${cfg.gnupgHome} \ ${pkgs.gnupg}/bin/gpgconf --launch gpg-agent ${head1} - fpr="$(${cfg.gpg-fingerprint}/bin/fingerprint -- "${uid}" | head1)" + fpr="$(${gpg-fingerprint}/bin/fingerprint -- "${uid}" | head1)" eval pass="\''${pass_$fpr}" if test -n "$pass" then @@ -190,7 +190,7 @@ let cfg = config.gnupg; keygrips="$keygrips $keygrip" echo >&2 "gpg: preset: keygrip=$keygrip pass=$pass" ${pkgs.pass}/bin/pass "$pass" | - GNUPGHOME=${cfg.dir.var} \ + GNUPGHOME=${cfg.gnupgHome} \ ${pkgs.gnupg}/libexec/gpg-preset-passphrase --preset ''${XTRACE:+--verbose} $keygrip done fi @@ -208,108 +208,83 @@ let cfg = config.gnupg; echo >&2 "INFO: $*" } ''; + + # A wrapper around gpg to set GNUPGHOME. + gpg-with-home = pkgs.writeScriptBin "gpg-with-home" '' + GNUPGHOME=${cfg.gnupgHome} \ + exec ${pkgs.gnupg}/bin/gpg "$@" + ''; + + # A wrapper around gpg to get fingerprints. + gpg-fingerprint = pkgs.writeScriptBin "gpg-fingerprint" '' + set -eu + ${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 + ''; + + # A wrapper around gpg to get keygrips. + gpg-keygrip = pkgs.writeScriptBin "gpg-keygrip" '' + set -eu + ${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 + ''; + + # A wrapper around gpg to get uids. + gpg-uid = pkgs.writeScriptBin "gpg-uid" '' + set -eu + ${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 + ''; + + # Initialize the keyring according to cfg.keys. + gpg-init = pkgs.writeShellScriptBin "gpg-init" ('' + set -eu + set -o pipefail + ${info} + info "Init GnuPG" + ${pkgs.coreutils}/bin/install -dm0700 -D ${cfg.gnupgHome} + ${pkgs.coreutils}/bin/ln -snf ${cfg.gpgConf} ${cfg.gnupgHome}/gpg.conf + ${pkgs.coreutils}/bin/ln -snf ${cfg.gpgAgentConf} ${cfg.gnupgHome}/gpg-agent.conf + ${pkgs.coreutils}/bin/ln -snf ${cfg.dirmngrConf} ${cfg.gnupgHome}/dirmngr.conf + '' + + generateKeys cfg.keys); in { options.gnupg = { - enable = lib.mkEnableOption "GnuPG admin utilities"; - dir.var = lib.mkOption { + enable = lib.mkEnableOption "GnuPG shell utilities"; + gnupgHome = 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 = @@ -410,14 +385,14 @@ in })); }; dirmngrConf = lib.mkOption { - type = types.str; + type = types.lines; 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 + #log-file ${cfg.gnupgHome}/dirmngr.log #standard-resolver ''; description = '' @@ -425,7 +400,7 @@ in ''; }; keyserverPEM = lib.mkOption { - type = types.str; + type = types.lines; apply = s: pkgs.writeText "keyserver.pem" s; default = builtins.readFile gnupg/keyserver.pem; description = '' @@ -433,7 +408,7 @@ in ''; }; gpgAgentConf = lib.mkOption { - type = types.str; + type = types.lines; apply = s: pkgs.writeText "gpg-agent.conf" s; default = '' allow-preset-passphrase @@ -448,7 +423,7 @@ in ''; }; gpgConf = lib.mkOption { - type = types.str; + type = types.lines; apply = s: pkgs.writeText "gpg.conf" s; default = '' auto-key-locate keyserver @@ -478,4 +453,21 @@ in ''; }; }; + config = lib.mkIf cfg.enable { + nix-shell.buildInputs = [ + gpg-with-home + gpg-fingerprint + gpg-keygrip + gpg-uid + gpg-init + ]; + nix-shell.shellHook = '' + # gnupg + export GNUPGHOME=${cfg.gnupgHome} + install -dm700 "$GNUPGHOME" + export GPG_TTY=$(${pkgs.coreutils}/bin/tty) + ${pkgs.gnupg}/bin/gpgconf --launch gpg-agent + export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket) + ''; + }; } -- 2.44.1 From 4aaebbbedfccd4fe6d2404959d7882dd4339c631 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Mon, 13 Jan 2020 23:20:50 +0000 Subject: [PATCH 06/16] mermet: add unlock target. --- Makefile | 1 - servers/mermet/Makefile | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4681f18..b1fd7b6 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,6 @@ all: init include .lib/nix/Makefile.make include .lib/nixops/Makefile.make -include servers/mermet/Makefile # ## init diff --git a/servers/mermet/Makefile b/servers/mermet/Makefile index 1a6b4e9..d59d696 100644 --- a/servers/mermet/Makefile +++ b/servers/mermet/Makefile @@ -248,3 +248,7 @@ umount: #sudo zpool export bpool ! sudo zpool list rpool 2>/dev/null || \ sudo zpool export rpool + +unlock: + pass servers/mermet/zfs/rpool | \ + nixops ssh mermet -p 2222 'zfs load-key rpool && pkill zfs' -- 2.44.1 From 7692f9a959c30a587571d3dc4b38d774c812fc09 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Mon, 13 Jan 2020 23:22:40 +0000 Subject: [PATCH 07/16] mermet: improve the boot --- servers/mermet/machine/apu2e4.nix | 17 ++++++++++------- shell.nix | 2 ++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/servers/mermet/machine/apu2e4.nix b/servers/mermet/machine/apu2e4.nix index 3aacd4f..ac66dd5 100644 --- a/servers/mermet/machine/apu2e4.nix +++ b/servers/mermet/machine/apu2e4.nix @@ -10,12 +10,6 @@ in boot.kernel = { sysctl = { - # Always reboot on a kernel panic, - # to not have to physically go power cycle the apu2e4. - # Which happens if the wrong ZFS password is used - # but the boot is manually forced to continue. - "kernel.panic" = 20; - "vm.swappiness" = 10; "vm.vfs_cache_pressure" = 50; }; @@ -88,10 +82,12 @@ in }; # this will automatically load the zfs password prompt on login # and kill the other prompt so boot can continue + # The pkill zfs kills the zfs load-key from the console + # allowing the boot to continue. postCommands = '' #zpool import rpool #/bin/ash - echo "zfs load-key -a; killall zfs" >> /root/.profile + echo "zfs load-key -a && pkill zfs" >> /root/.profile ''; }; @@ -99,6 +95,13 @@ in boot.kernelModules = [ ]; boot.extraModulePackages = [ ]; boot.kernelParams = [ + # Always reboot on a kernel panic, + # to not have to physically go power cycle the apu2e4. + # Which happens if the wrong ZFS password is used + # but the boot is manually forced to continue. + # Using kernelParams instead of kernel.sysctl + # sets this up as soon as the initrd. + "panic=10" "gfxpayload=text" "console=tty0" "console=ttyS0,115200n8" diff --git a/shell.nix b/shell.nix index 8d63df7..ca831c2 100644 --- a/shell.nix +++ b/shell.nix @@ -21,6 +21,8 @@ let openssh = { enable = true; sshConf = '' + HashKnownHosts no + UserKnownHostsFile ${builtins.toString .ssh/known_hosts} ''; }; }; -- 2.44.1 From d865186a0264ccedca00883d9c4e4990dd61bd96 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Mon, 13 Jan 2020 23:23:17 +0000 Subject: [PATCH 08/16] nix: fix nix wrapper --- shell.nix | 11 +++++------ .../modules/development/libraries/nix-plugins.nix | 3 +++ shell/modules/tools/package-management/nix.nix | 14 ++++++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/shell.nix b/shell.nix index ca831c2..8dbe8d1 100644 --- a/shell.nix +++ b/shell.nix @@ -10,6 +10,11 @@ let configuration = {config, ...}: { imports = [ ]; + nix = { + nixConf = '' + auto-optimise-store = true + ''; + }; nix-plugins = { enable = true; }; @@ -133,13 +138,7 @@ pkgs.stdenv.mkDerivation { # nixops #export NIXOPS_DEPLOYMENT="staging" export NIXOPS_STATE="$PWD"/.sec/nixops/state.nixops - # Extend the Nix interpreter - # to enable builtins.extraBuiltins, - # which provides an unsafe exec useful to get secrets - # 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 ${modules.nix-plugins.extra-builtins}" export NIXOPS_OPTS # disnix diff --git a/shell/modules/development/libraries/nix-plugins.nix b/shell/modules/development/libraries/nix-plugins.nix index a1a2798..df8d910 100644 --- a/shell/modules/development/libraries/nix-plugins.nix +++ b/shell/modules/development/libraries/nix-plugins.nix @@ -1,3 +1,6 @@ +# Extend the Nix interpreter to enable builtins.extraBuiltins, +# which provides an unsafe exec. +# Useful to get secrets from a local password-store. { config, lib, pkgs, ... }: let cfg = config.nix-plugins; inherit (lib) types; diff --git a/shell/modules/tools/package-management/nix.nix b/shell/modules/tools/package-management/nix.nix index 88c0da6..37ccd87 100644 --- a/shell/modules/tools/package-management/nix.nix +++ b/shell/modules/tools/package-management/nix.nix @@ -1,8 +1,11 @@ { config, lib, pkgs, ... }: let cfg = config.nix; inherit (lib) types; - /* Alternative which does not need to re-export envvars when called via sudo. - But this is maybe more clear to just (re-)export envvars. + # Alternative which does not need to re-export envvars when called via sudo. + # But this is maybe more clear to just (re-)export envvars. + # And anyway, using NIX_CONF_DIR=${cfg.nixConf} directly does not work, + # maybe because of filesystem restriction access set by nix, I don't know. + /* nix = pkgs.writeShellScriptBin "nix" '' NIX_CONF_DIR=${cfg.nixConf} \ NIX_SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" \ @@ -26,10 +29,13 @@ in }; }; config = lib.mkIf cfg.enable { - #shell.buildInputs = [ nix ]; + #nix-shell.buildInputs = [ nix ]; nix-shell.shellHook = '' # nix - export NIX_CONF_DIR=${cfg.nixConf} + # NOTE: linking NIX_CONF_DIR directly to ${cfg.nixConf} does not work. + mkdir -p "$PWD"/.config/nix + ln -fns ${cfg.nixConf} "$PWD"/.config/nix/nix.conf + export NIX_CONF_DIR="$PWD"/.config/nix export NIX_SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" export SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ''; -- 2.44.1 From f2af051f5396de121413231df4463fb417e0729c Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Tue, 14 Jan 2020 07:57:31 +0000 Subject: [PATCH 09/16] nix: add admin tools and setup shorewall --- nixos/defaults.nix | 4 + nixos/modules.nix | 1 + .../modules/services/networking/shorewall.nix | 2 - .../services/networking/shorewall6.nix | 75 +++++++++ overlays.nix | 7 +- .../smartmontools/smartctl-tbw/default.nix | 64 +++++++ servers/mermet/machine/apu2e4.nix | 27 ++- servers/mermet/system.nix | 7 +- servers/mermet/system/shorewall.nix | 156 ++++++++++++++++++ servers/mermet/system/zfs.nix | 17 +- .../modules/tools/package-management/nix.nix | 2 +- 11 files changed, 344 insertions(+), 18 deletions(-) create mode 100644 nixos/modules/services/networking/shorewall6.nix create mode 100644 pkgs/tools/system/smartmontools/smartctl-tbw/default.nix create mode 100644 servers/mermet/system/shorewall.nix diff --git a/nixos/defaults.nix b/nixos/defaults.nix index 30ab620..254d2a7 100644 --- a/nixos/defaults.nix +++ b/nixos/defaults.nix @@ -1,4 +1,6 @@ { pkgs, lib, config, ... }: +let inherit (lib) types; +in { imports = [ ./modules.nix @@ -64,9 +66,11 @@ config = { dnsutils htop inetutils + iotop mailutils multitail ncdu + pv tcpdump tmux tree diff --git a/nixos/modules.nix b/nixos/modules.nix index 13ff500..d62ffc3 100644 --- a/nixos/modules.nix +++ b/nixos/modules.nix @@ -5,6 +5,7 @@ modules/services/mail/dovecot.nix modules/services/networking/domains.nix modules/services/networking/shorewall.nix + modules/services/networking/shorewall6.nix #modules/services/security/x509.nix ]; } diff --git a/nixos/modules/services/networking/shorewall.nix b/nixos/modules/services/networking/shorewall.nix index 75d65bf..0f94d41 100644 --- a/nixos/modules/services/networking/shorewall.nix +++ b/nixos/modules/services/networking/shorewall.nix @@ -39,7 +39,6 @@ in { }; config = lib.mkIf cfg.enable { - /* systemd.services.firewall.enable = false; systemd.services.shorewall = { description = "Shorewall IPv4 Firewall"; @@ -72,6 +71,5 @@ in { cfg.configs; systemPackages = [ cfg.package ]; }; - */ }; } diff --git a/nixos/modules/services/networking/shorewall6.nix b/nixos/modules/services/networking/shorewall6.nix new file mode 100644 index 0000000..9c22a03 --- /dev/null +++ b/nixos/modules/services/networking/shorewall6.nix @@ -0,0 +1,75 @@ +{ 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. + + + Enabling this service WILL disable the existing NixOS + firewall! Default firewall rules provided by packages are not + considered at the moment. + + + ''; + }; + 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/overlays.nix b/overlays.nix index 04e6e2a..6251a43 100644 --- a/overlays.nix +++ b/overlays.nix @@ -6,6 +6,7 @@ map import # 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 {}; }) -]*/ +] ++ +[ (self: super: { shorewall = super.callPackage pkgs/tools/networking/shorewall {}; }) + (self: super: { smartctl-tbw = super.callPackage pkgs/tools/system/smartmontools/smartctl-tbw {}; }) +] diff --git a/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix b/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix new file mode 100644 index 0000000..f35db10 --- /dev/null +++ b/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix @@ -0,0 +1,64 @@ +{ coreutils +, gawk +, gnused +, smartmontools +, stdenv +, sudo +, writeShellScriptBin +, utillinux +}: +let + PATH = stdenv.lib.concatStringsSep ":" + [ "${coreutils}/bin" + "${gawk}/bin" + "${gnused}/bin" + "${sudo}/bin" + "${utillinux}/bin" + ]; +in +stdenv.mkDerivation rec { + pname = "smartctl-tbw"; + version = "1.0"; + name = "${pname}-${version}"; + + src = writeShellScriptBin "smartctl-tbw" '' + export PATH=${PATH} + device=''${1:-/dev/sda} + sudo ${smartmontools}/bin/smartctl -A $device | + awk ' + $0 ~ /Power_On_Hours/ { poh=$10; printf "%s / %d hours / %d days / %.2f years\n", $2, $10, $10 / 24, $10 / 24 / 365.25 } + $0 ~ /Total_LBAs_Written/ { + lbas=$10; + bytes=$10 * 512; + mb= bytes / 1024^2; + gb= bytes / 1024^3; + tb= bytes / 1024^4; + printf "%s / %s / %d mb / %.1f gb / %.3f tb\n", $2, $10, mb, gb, tb + printf "mean writes per hour: / %.2f", mb/poh + } + $0 ~ /Airflow_Temperature_Cel/ { print $2 " / " $10} + $0 ~ /Wear_Leveling_Count/ { printf "%s / %d (%% health)\n", $2, int($4) } + ' | + sed -e 's:/:@:' | + sed -e "s\$^\$$device @ \$" | + column -ts@ + ''; + + buildInputs = [ + gawk + coreutils + gnused + smartmontools + sudo + utillinux + ]; + installPhase = '' + cp -r . $out + ''; + + meta = { + description = "Wrapper around smartctl to print the Total-Bytes-Written of disks"; + license = stdenv.lib.licenses.gpl3Plus; + platforms = stdenv.lib.platforms.all; + }; +} diff --git a/servers/mermet/machine/apu2e4.nix b/servers/mermet/machine/apu2e4.nix index ac66dd5..932306b 100644 --- a/servers/mermet/machine/apu2e4.nix +++ b/servers/mermet/machine/apu2e4.nix @@ -75,9 +75,7 @@ in 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" + (pass "members/julm/ssh.pub") ]; }; # this will automatically load the zfs password prompt on login @@ -85,9 +83,7 @@ in # The pkill zfs kills the zfs load-key from the console # allowing the boot to continue. postCommands = '' - #zpool import rpool - #/bin/ash - echo "zfs load-key -a && pkill zfs" >> /root/.profile + echo >>/root/.profile "zfs load-key -a && pkill zfs" ''; }; @@ -132,6 +128,25 @@ in nix.maxJobs = lib.mkDefault 4; powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; + networking = { + zones = { + net = { + iface = "enp1s0"; + #ipv4 = ipv4; + }; + maint = { + iface = "enp2s0"; + #ipv4 = ipv4; + #ipv6 = "fe80::1"; + }; + unused = { + iface = "enp3s0"; + #ipv4 = ipv4; + #ipv6 = "fe80::1"; + }; + }; + }; + environment = { systemPackages = with pkgs; [ pciutils diff --git a/servers/mermet/system.nix b/servers/mermet/system.nix index ff1ca45..21f971c 100644 --- a/servers/mermet/system.nix +++ b/servers/mermet/system.nix @@ -4,6 +4,7 @@ in { imports = [ ./system/zfs.nix + ./system/shorewall.nix ]; # This value determines the NixOS release with which your system is to be @@ -37,7 +38,11 @@ in environment = { systemPackages = with pkgs; [ cryptsetup - zfs + fio + git + gptfdisk + lm_sensors + smartctl-tbw ]; }; } diff --git a/servers/mermet/system/shorewall.nix b/servers/mermet/system/shorewall.nix new file mode 100644 index 0000000..798c96c --- /dev/null +++ b/servers/mermet/system/shorewall.nix @@ -0,0 +1,156 @@ +{ 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 + net enp1s0 arp_filter,nosmurfs,routefilter,tcpflags + maint enp2s0 arp_filter,nosmurfs,routefilter,tcpflags,dhcp + unused enp3s0 arp_filter,nosmurfs,routefilter,tcpflags + ''; + /* + 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 + SSH(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/servers/mermet/system/zfs.nix b/servers/mermet/system/zfs.nix index ed495c7..df3930a 100644 --- a/servers/mermet/system/zfs.nix +++ b/servers/mermet/system/zfs.nix @@ -10,14 +10,14 @@ # Manually generated with : head -c4 /dev/urandom | od -A none -t x4 | cut -d ' ' -f 2 networking.hostId = "69c40b03"; - # noop, the recommended elevator with zfs. + # noop is the recommended elevator with zfs. boot.kernelParams = [ "elevator=noop" ]; - # FIXME: Uncomment [on a working system] to ensure extra safeguards are active that zfs uses to protect zfs pools: - #boot.zfs.forceImportAll = false; - #boot.zfs.forceImportRoot = false; + # Ensure extra safeguards are active that zfs uses to protect zfs pools. + boot.zfs.forceImportAll = false; + boot.zfs.forceImportRoot = false; boot.zfs.enableUnstable = true; boot.zfs.requestEncryptionCredentials = true; @@ -25,6 +25,13 @@ # Enables periodic scrubbing of ZFS pools. services.zfs.autoScrub.enable = true; + environment = { + systemPackages = [ + pkgs.mbuffer + pkgs.zfs + ]; + }; + /* # Enable the (OpenSolaris-compatible) ZFS auto-snapshotting service. services.zfs.autoSnapshot = { @@ -36,6 +43,7 @@ monthly = ; }; */ + /* fileSystems."/boot" = { device = "bpool/boot"; @@ -91,5 +99,4 @@ { device = "rpool/var/www"; fsType = "zfs"; }; - } diff --git a/shell/modules/tools/package-management/nix.nix b/shell/modules/tools/package-management/nix.nix index 37ccd87..041e0d2 100644 --- a/shell/modules/tools/package-management/nix.nix +++ b/shell/modules/tools/package-management/nix.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ pkgs, lib, config, ... }: let cfg = config.nix; inherit (lib) types; # Alternative which does not need to re-export envvars when called via sudo. -- 2.44.1 From 234953b383bdc5056056bad7c9222dda2cb12ee7 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Tue, 14 Jan 2020 08:45:40 +0000 Subject: [PATCH 10/16] nix: add mem and swaplist --- nixos/defaults.nix | 2 + overlays.nix | 1 + .../smartmontools/smartctl-tbw/default.nix | 83 +++++++------------ pkgs/tools/system/swaplist/default.nix | 35 ++++++++ 4 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 pkgs/tools/system/swaplist/default.nix diff --git a/nixos/defaults.nix b/nixos/defaults.nix index 254d2a7..d2e9704 100644 --- a/nixos/defaults.nix +++ b/nixos/defaults.nix @@ -71,6 +71,7 @@ config = { multitail ncdu pv + swaplist tcpdump tmux tree @@ -99,6 +100,7 @@ config = { l = "ls -alh"; ll = "ls -l"; ls = "ls --color=tty"; + mem = "ps -e -orss=,user=,args= | sort -b -k1,1n"; s="sudo systemctl"; s-u="systemctl --user"; diff --git a/overlays.nix b/overlays.nix index 6251a43..58252a9 100644 --- a/overlays.nix +++ b/overlays.nix @@ -9,4 +9,5 @@ map import ] ++ [ (self: super: { shorewall = super.callPackage pkgs/tools/networking/shorewall {}; }) (self: super: { smartctl-tbw = super.callPackage pkgs/tools/system/smartmontools/smartctl-tbw {}; }) + (self: super: { swaplist = super.callPackage pkgs/tools/system/swaplist {}; }) ] diff --git a/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix b/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix index f35db10..0886051 100644 --- a/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix +++ b/pkgs/tools/system/smartmontools/smartctl-tbw/default.nix @@ -7,58 +7,33 @@ , writeShellScriptBin , utillinux }: -let - PATH = stdenv.lib.concatStringsSep ":" - [ "${coreutils}/bin" - "${gawk}/bin" - "${gnused}/bin" - "${sudo}/bin" - "${utillinux}/bin" - ]; -in -stdenv.mkDerivation rec { - pname = "smartctl-tbw"; - version = "1.0"; - name = "${pname}-${version}"; - - src = writeShellScriptBin "smartctl-tbw" '' - export PATH=${PATH} - device=''${1:-/dev/sda} - sudo ${smartmontools}/bin/smartctl -A $device | - awk ' - $0 ~ /Power_On_Hours/ { poh=$10; printf "%s / %d hours / %d days / %.2f years\n", $2, $10, $10 / 24, $10 / 24 / 365.25 } - $0 ~ /Total_LBAs_Written/ { - lbas=$10; - bytes=$10 * 512; - mb= bytes / 1024^2; - gb= bytes / 1024^3; - tb= bytes / 1024^4; - printf "%s / %s / %d mb / %.1f gb / %.3f tb\n", $2, $10, mb, gb, tb - printf "mean writes per hour: / %.2f", mb/poh - } - $0 ~ /Airflow_Temperature_Cel/ { print $2 " / " $10} - $0 ~ /Wear_Leveling_Count/ { printf "%s / %d (%% health)\n", $2, int($4) } - ' | - sed -e 's:/:@:' | - sed -e "s\$^\$$device @ \$" | - column -ts@ - ''; - - buildInputs = [ - gawk - coreutils - gnused - smartmontools - sudo - utillinux +let PATH = stdenv.lib.concatStringsSep ":" + [ "${coreutils}/bin" + "${gawk}/bin" + "${gnused}/bin" + "${sudo}/bin" + "${utillinux}/bin" ]; - installPhase = '' - cp -r . $out - ''; - - meta = { - description = "Wrapper around smartctl to print the Total-Bytes-Written of disks"; - license = stdenv.lib.licenses.gpl3Plus; - platforms = stdenv.lib.platforms.all; - }; -} +in +writeShellScriptBin "smartctl-tbw" '' + export PATH=${PATH} + device=''${1:-/dev/sda} + sudo ${smartmontools}/bin/smartctl -A $device | + awk ' + $0 ~ /Power_On_Hours/ { poh=$10; printf "%s / %d hours / %d days / %.2f years\n", $2, $10, $10 / 24, $10 / 24 / 365.25 } + $0 ~ /Total_LBAs_Written/ { + lbas=$10; + bytes=$10 * 512; + mb= bytes / 1024^2; + gb= bytes / 1024^3; + tb= bytes / 1024^4; + printf "%s / %s / %d mb / %.1f gb / %.3f tb\n", $2, $10, mb, gb, tb + printf "mean writes per hour: / %.2f", mb/poh + } + $0 ~ /Airflow_Temperature_Cel/ { print $2 " / " $10} + $0 ~ /Wear_Leveling_Count/ { printf "%s / %d (%% health)\n", $2, int($4) } + ' | + sed -e 's:/:@:' | + sed -e "s\$^\$$device @ \$" | + column -ts@ +'' diff --git a/pkgs/tools/system/swaplist/default.nix b/pkgs/tools/system/swaplist/default.nix new file mode 100644 index 0000000..e203e5b --- /dev/null +++ b/pkgs/tools/system/swaplist/default.nix @@ -0,0 +1,35 @@ +{ coreutils +, stdenv +, writeShellScriptBin +}: +let PATH = stdenv.lib.concatStringsSep ":" [ "${coreutils}/bin" ]; +in +writeShellScriptBin "swaplist" '' + # SYNTAX: + # DESCRIPTION: print sorted swap usage of processes using it + export PATH=${PATH} + lastpid= + swap=0 + sudo grep -H '^Swap:' /proc/*/smaps 2>/dev/null | + while IFS=: read -r file x size x + do + pid=''${file#/proc/} + pid=''${pid%/smaps} + size=''${size% kB} + size=''${size##* } + if test "$pid" = "$lastpid" + then swap=$(( swap + size )) + else + if test "$swap" -gt 0 + then printf "%u pid=%u cmd=%s\n" "$swap" "$lastpid" "$(tr '\000' ' ' Date: Tue, 14 Jan 2020 09:04:51 +0000 Subject: [PATCH 11/16] nix: set scheduler to none for ZFS and SSD --- servers/mermet/system/zfs.nix | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/servers/mermet/system/zfs.nix b/servers/mermet/system/zfs.nix index df3930a..b07df31 100644 --- a/servers/mermet/system/zfs.nix +++ b/servers/mermet/system/zfs.nix @@ -10,10 +10,12 @@ # Manually generated with : head -c4 /dev/urandom | od -A none -t x4 | cut -d ' ' -f 2 networking.hostId = "69c40b03"; - # noop is the recommended elevator with zfs. - boot.kernelParams = [ - "elevator=noop" - ]; + # none is the recommended elevator with ZFS (which has its own I/O scheduler) + # and/or for SSD, whereas HDD could use mq-deadline. + services.udev.extraRules = '' + # set none scheduler for non-rotating disks + ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none" + ''; # Ensure extra safeguards are active that zfs uses to protect zfs pools. boot.zfs.forceImportAll = false; -- 2.44.1 From e5282a7d015d2c6791bf7666c44ea8d8721e9539 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Tue, 14 Jan 2020 09:19:00 +0000 Subject: [PATCH 12/16] ssh: StrictHostKeyChecking=yes --- shell.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/shell.nix b/shell.nix index 8dbe8d1..43ad2e0 100644 --- a/shell.nix +++ b/shell.nix @@ -27,6 +27,7 @@ let enable = true; sshConf = '' HashKnownHosts no + StrictHostKeyChecking yes UserKnownHostsFile ${builtins.toString .ssh/known_hosts} ''; }; -- 2.44.1 From 83cdfc841ab76edcad4720946750ac72354298f7 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Wed, 15 Jan 2020 03:54:22 +0000 Subject: [PATCH 13/16] nix: fix trailing newline in pass --- shell/modules/development/libraries/nix-plugins.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/modules/development/libraries/nix-plugins.nix b/shell/modules/development/libraries/nix-plugins.nix index df8d910..03f9c5b 100644 --- a/shell/modules/development/libraries/nix-plugins.nix +++ b/shell/modules/development/libraries/nix-plugins.nix @@ -20,7 +20,9 @@ let cfg = config.nix-plugins; set -e f=$(mktemp) trap "shred -u $f" EXIT - ${pkgs.pass}/bin/pass show "$1" >$f + # NOTE: using an envvar removes the trailing newline added by pass generate + pass="$(${pkgs.pass}/bin/pass show "$1")" + printf %s "$pass" >$f nix-instantiate --eval -E "builtins.readFile $f" ''; /* -- 2.44.1 From c1a84271ccc93dcb5d9cb585a00ed9d206f41011 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Wed, 15 Jan 2020 03:54:52 +0000 Subject: [PATCH 14/16] mermet: fix shorewall --- nixos/modules/services/networking/domains.nix | 21 --- servers/mermet.nix | 6 +- servers/mermet/hosting/lan.nix | 8 - servers/mermet/hosting/ptt.nix | 27 ++- servers/mermet/machine/apu2e4.nix | 23 +-- servers/mermet/machine/virtualbox.nix | 21 +-- servers/mermet/system/shorewall.nix | 175 +++++++++--------- 7 files changed, 118 insertions(+), 163 deletions(-) delete mode 100644 servers/mermet/hosting/lan.nix diff --git a/nixos/modules/services/networking/domains.nix b/nixos/modules/services/networking/domains.nix index 664935d..f503dcb 100644 --- a/nixos/modules/services/networking/domains.nix +++ b/nixos/modules/services/networking/domains.nix @@ -12,26 +12,5 @@ options.networking = { description = "Domain aliases."; example = [ "example.org" "example.net" ]; }; - zones = lib.mkOption { - type = types.attrsOf (types.submodule ({name, options, config, ...}: { - options = { - iface = lib.mkOption { - type = types.str; - description = "Interface name."; - example = "eth0"; - }; - ipv4 = lib.mkOption { - type = types.str; - description = "Static IPv4 address of the machine."; - example = "1.2.3.4"; - }; - ipv6 = lib.mkOption { - type = types.str; - description = "Static IPv6 address of the machine."; - example = "fe80::1"; - }; - }; - })); - }; }; } diff --git a/servers/mermet.nix b/servers/mermet.nix index eaa2476..9798518 100644 --- a/servers/mermet.nix +++ b/servers/mermet.nix @@ -5,13 +5,9 @@ {pkgs, lib, config, options, nodes, resources, ...}: let deployment = builtins.getAttr - (lib.maybeEnv "NIXOPS_DEPLOYMENT" "production") + ( lib.maybeEnv "NIXOPS_DEPLOYMENT" "production") deployments; deployments = { - maintenance = [ - mermet/machine/apu2e4.nix - mermet/hosting/lan.nix - ]; production = [ mermet/machine/apu2e4.nix mermet/hosting/ptt.nix diff --git a/servers/mermet/hosting/lan.nix b/servers/mermet/hosting/lan.nix deleted file mode 100644 index 894e9e7..0000000 --- a/servers/mermet/hosting/lan.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ pkgs, lib, config, ... }: -{ - networking = { - interfaces.enp1s0.useDHCP = true; - #interfaces.enp2s0.useDHCP = true; - #interfaces.enp3s0.useDHCP = true; - }; -} diff --git a/servers/mermet/hosting/ptt.nix b/servers/mermet/hosting/ptt.nix index 21e42ee..fc94be2 100644 --- a/servers/mermet/hosting/ptt.nix +++ b/servers/mermet/hosting/ptt.nix @@ -1,11 +1,26 @@ { pkgs, lib, config, nodes, ... }: +let targetHost = "192.168.1.214"; in { networking = { - interfaces.enp1s0.useDHCP = true; - #interfaces.enp2s0.useDHCP = true; - #interfaces.enp3s0.useDHCP = true; + useDHCP = false; + interfaces.enp1s0 = { + useDHCP = false; + ipv4.addresses = [ + { address = targetHost; + prefixLength = 32; + } + ]; + ipv4.routes = [ + ]; + }; + interfaces.enp2s0 = { + useDHCP = true; + }; + interfaces.enp3s0 = { + useDHCP = false; + }; + }; + deployment = lib.mkIf (builtins.hasAttr "mermet" nodes) { + inherit targetHost; }; -} -// lib.mkIf (builtins.hasAttr "mermet" nodes) { - deployment.targetHost = "1.2.3.4"; } diff --git a/servers/mermet/machine/apu2e4.nix b/servers/mermet/machine/apu2e4.nix index 932306b..0acf967 100644 --- a/servers/mermet/machine/apu2e4.nix +++ b/servers/mermet/machine/apu2e4.nix @@ -1,7 +1,5 @@ { pkgs, lib, config, ... }: -let inherit (builtins.extraBuiltins) pass pass-to-file; - inherit (config) networking; - userPass = name: pass "${networking.domainBase}/${networking.hostName}/login/${name}"; +let inherit (builtins.extraBuiltins) pass; in { imports = @@ -128,25 +126,6 @@ in nix.maxJobs = lib.mkDefault 4; powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; - networking = { - zones = { - net = { - iface = "enp1s0"; - #ipv4 = ipv4; - }; - maint = { - iface = "enp2s0"; - #ipv4 = ipv4; - #ipv6 = "fe80::1"; - }; - unused = { - iface = "enp3s0"; - #ipv4 = ipv4; - #ipv6 = "fe80::1"; - }; - }; - }; - environment = { systemPackages = with pkgs; [ pciutils diff --git a/servers/mermet/machine/virtualbox.nix b/servers/mermet/machine/virtualbox.nix index 1d6fcd5..6e8cf7a 100644 --- a/servers/mermet/machine/virtualbox.nix +++ b/servers/mermet/machine/virtualbox.nix @@ -1,14 +1,13 @@ { pkgs, lib, config, options, nodes, ... }: { -} -// lib.mkIf (builtins.hasAttr "mermet" nodes) { - 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; + deployment = lib.mkIf (builtins.hasAttr "mermet" nodes) { + targetEnv = "virtualbox"; + virtualbox.headless = true; + virtualbox.memorySize = 1024; + virtualbox.vcpu = 2; + virtualbox.disks.disk1.baseImage = ../../../.cache/nixops/virtualbox/nixops.vmdk; + # NOTE: resize not yet supported. + #virtualbox.disks.disk1.size = 6024; + storeKeysOnMachine = true; + }; } diff --git a/servers/mermet/system/shorewall.nix b/servers/mermet/system/shorewall.nix index 798c96c..0d5788c 100644 --- a/servers/mermet/system/shorewall.nix +++ b/servers/mermet/system/shorewall.nix @@ -1,21 +1,57 @@ { 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; +let + inherit (builtins) hasAttr readFile; + inherit (pkgs.lib) unlinesAttrs; + inherit (config.services) shorewall shorewall6; + fw2net = '' + # 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 + ''; + net2fw = '' + # 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 + SSH(ACCEPT) net $FW + ''; + fw2lan = '' + Ping(ACCEPT) $FW lan + DNS(ACCEPT) $FW lan + HTTPS(ACCEPT) $FW lan + ''; + lan2fw = '' + Ping(ACCEPT) lan $FW + SSH(ACCEPT) lan $FW + ''; + macros = { "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 = { + configs = macros // { "shorewall.conf" = '' ${readFile "${shorewall.package}/etc-example/shorewall/shorewall.conf"} # @@ -23,87 +59,48 @@ config = { ### STARTUP_ENABLED=Yes ZONE2ZONE=2 - ''; + ''; zones = '' # DOC: shorewall-zones(5) fw firewall - '' + unlinesAttrs (zone: _: "${zone} ipv4") zones4; + net ipv4 + lan ipv4 + unused ipv4 + ''; interfaces = '' # DOC: shorewall-interfaces(5) ?FORMAT 2 - net enp1s0 arp_filter,nosmurfs,routefilter,tcpflags - maint enp2s0 arp_filter,nosmurfs,routefilter,tcpflags,dhcp - unused enp3s0 arp_filter,nosmurfs,routefilter,tcpflags - ''; - /* + unlinesAttrs (zone: {iface, ...}: - "${zone} ${iface} arp_filter,nosmurfs,routefilter,tcpflags") zones4 - */ + net enp1s0 arp_filter,nosmurfs,routefilter=1,tcpflags + lan enp2s0 arp_filter,nosmurfs,routefilter=1,tcpflags,dhcp + unused enp3s0 arp_filter,nosmurfs,routefilter=1,tcpflags + ''; 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 - ''; + $FW all DROP + lan all DROP none + net all DROP none + unused all DROP none + # WARNING: 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 + ${fw2net} + ${net2fw} - # 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 - SSH(ACCEPT) net $FW - ''; - inherit "macro.Git"; + ${fw2lan} + ${lan2fw} + ''; }; }; services.shorewall6 = { enable = true; - configs = { + configs = macros // { "shorewall6.conf" = '' ${readFile "${shorewall6.package}/etc-example/shorewall6/shorewall6.conf"} # @@ -115,41 +112,39 @@ config = { zones = '' # DOC: shorewall-zones(5) fw firewall - '' + unlinesAttrs (zone: _: "${zone} ipv6") zones6; + net ipv6 + lan ipv6 + unused ipv6 + ''; interfaces = '' # DOC: shorewall-interfaces(5) ?FORMAT 2 - '' + unlinesAttrs (zone: {iface, ...}: "${zone} ${iface} nosmurfs,tcpflags") zones6; + net enp1s0 nosmurfs,tcpflags + lan enp2s0 nosmurfs,tcpflags + unused enp3s0 nosmurfs,tcpflags + ''; 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 - ''; + $FW all DROP + lan all DROP none + net all DROP none + unused all DROP none + # WARNING: 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"; + ${fw2net} + ${net2fw} + + ${fw2lan} + ${lan2fw} + ''; }; }; }; -- 2.44.1 From 9d3f0bf9c4fa0d77d33fe0db44f59d9d205f5e14 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Wed, 15 Jan 2020 04:26:05 +0000 Subject: [PATCH 15/16] mermet: move rpool/nix/var to rpool/nix --- nixos/defaults.nix | 1 + servers/mermet/Makefile | 6 ------ servers/mermet/system/zfs.nix | 5 ----- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/nixos/defaults.nix b/nixos/defaults.nix index d2e9704..8bcdb1a 100644 --- a/nixos/defaults.nix +++ b/nixos/defaults.nix @@ -67,6 +67,7 @@ config = { htop inetutils iotop + lsof mailutils multitail ncdu diff --git a/servers/mermet/Makefile b/servers/mermet/Makefile index d59d696..dd4e0b5 100644 --- a/servers/mermet/Makefile +++ b/servers/mermet/Makefile @@ -112,7 +112,6 @@ format: for p in \ home \ nix \ - nix/var \ var \ var/cache \ var/log \ @@ -129,9 +128,6 @@ format: sudo zfs set \ com.sun:auto-snapshot=false \ rpool/nix - sudo zfs set \ - sync=always \ - rpool/nix/var sudo zfs set \ com.sun:auto-snapshot=false \ rpool/var/cache @@ -169,7 +165,6 @@ mount: for p in \ home \ nix \ - nix/var \ var \ var/cache \ var/log \ @@ -225,7 +220,6 @@ umount: boot/efi \ boot \ home \ - nix/var \ nix \ var/cache \ var/log \ diff --git a/servers/mermet/system/zfs.nix b/servers/mermet/system/zfs.nix index b07df31..ad177c0 100644 --- a/servers/mermet/system/zfs.nix +++ b/servers/mermet/system/zfs.nix @@ -67,11 +67,6 @@ fsType = "zfs"; }; - fileSystems."/nix/var" = - { device = "rpool/nix/var"; - fsType = "zfs"; - }; - fileSystems."/var" = { device = "rpool/var"; fsType = "zfs"; -- 2.44.1 From 7b2bd623e4491c32d497840cd1e62e29daab49bf Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Wed, 15 Jan 2020 05:44:32 +0000 Subject: [PATCH 16/16] mermet: flatten the conf --- nixos/defaults.nix | 3 ++ servers/mermet.nix | 47 ++++++++++++++++-- servers/mermet/Makefile | 4 +- servers/mermet/{machine => }/apu2e4.nix | 2 +- .../mermet/{hosting/ptt.nix => lesptts.nix} | 7 +-- servers/mermet/{hosting => }/localhost.nix | 11 ----- servers/mermet/{machine => }/sfdisk.txt | 0 servers/mermet/{system => }/shorewall.nix | 0 servers/mermet/system.nix | 48 ------------------- servers/mermet/{machine => }/virtualbox.nix | 0 servers/mermet/{system => }/zfs.nix | 0 11 files changed, 52 insertions(+), 70 deletions(-) rename servers/mermet/{machine => }/apu2e4.nix (98%) rename servers/mermet/{hosting/ptt.nix => lesptts.nix} (75%) rename servers/mermet/{hosting => }/localhost.nix (70%) rename servers/mermet/{machine => }/sfdisk.txt (100%) rename servers/mermet/{system => }/shorewall.nix (100%) delete mode 100644 servers/mermet/system.nix rename servers/mermet/{machine => }/virtualbox.nix (100%) rename servers/mermet/{system => }/zfs.nix (100%) diff --git a/nixos/defaults.nix b/nixos/defaults.nix index 8bcdb1a..1ffc2ad 100644 --- a/nixos/defaults.nix +++ b/nixos/defaults.nix @@ -37,6 +37,9 @@ config = { enable = false; # NOTE: useless on this machine, and CPU intensive. }; + # Clean /tmp automatically on boot. + boot.cleanTmpDir = true; + time = { timeZone = "Europe/Paris"; }; diff --git a/servers/mermet.nix b/servers/mermet.nix index 9798518..d271dbf 100644 --- a/servers/mermet.nix +++ b/servers/mermet.nix @@ -4,24 +4,61 @@ # only the resulting closure is copied to the target machine. {pkgs, lib, config, options, nodes, resources, ...}: let + inherit (builtins.extraBuiltins) pass; deployment = builtins.getAttr ( lib.maybeEnv "NIXOPS_DEPLOYMENT" "production") deployments; deployments = { production = [ - mermet/machine/apu2e4.nix - mermet/hosting/ptt.nix ]; staging = [ - mermet/machine/virtualbox.nix - mermet/hosting/localhost.nix ]; }; in { + # 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? + nixpkgs.overlays = import ../overlays.nix; + imports = [ ../nixos/defaults.nix - mermet/system.nix + mermet/apu2e4.nix + mermet/zfs.nix + mermet/lesptts.nix + mermet/shorewall.nix ] ++ deployment; + + networking = { + hostName = "mermet"; + domain = "sourcephile.fr"; + }; + + users = { + mutableUsers = false; + users = { + root = rec { + initialPassword = password; + password = pass "servers/mermet/login/root"; + openssh.authorizedKeys.keys = [ + (pass "members/julm/ssh.pub") + ]; + }; + }; + groups = { + }; + }; + + environment = { + systemPackages = with pkgs; [ + cryptsetup + fio + git + gptfdisk + lm_sensors + smartctl-tbw + ]; + }; } diff --git a/servers/mermet/Makefile b/servers/mermet/Makefile index dd4e0b5..e24661b 100644 --- a/servers/mermet/Makefile +++ b/servers/mermet/Makefile @@ -1,6 +1,6 @@ #cwd := $(notdir $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))) NIXOPS_DEPLOYMENT := maintenance -mermet_disk := $(shell sed -ne 's/^device: \(.*\)/\1/p' machine/sfdisk.txt) +mermet_disk := $(shell sed -ne 's/^device: \(.*\)/\1/p' sfdisk.txt) #mermet_cipher := mermet_cipher := aes-128-gcm mermet_autotrim := @@ -17,7 +17,7 @@ wipeout: umount partition: sudo modprobe zfs - sudo $$(which sfdisk) $(mermet_disk)