From 9887c48e648312ee6f0be07bce877cb0e3f87aeb Mon Sep 17 00:00:00 2001
From: Julien Moutinho <julm@sourcephile.fr>
Date: Tue, 21 Jul 2020 10:47:55 +0200
Subject: [PATCH] nix: use nixpkgs/patches/ instead of nixos/modules/

---
 .envrc                                        |   2 +-
 machines/losurdo.nix                          |   4 +-
 machines/losurdo/security.nix                 |   6 +-
 machines/mermet.nix                           |   4 +-
 machines/mermet/security.nix                  |   6 +-
 nixos/modules.nix                             |   2 -
 nixos/modules/install/ssh-nixos.nix           |  96 ---------
 nixpkgs/patches/installer.ssh-nixos.diff      | 130 +++++++++++++
 nixpkgs/patches/security.pass.diff            | 183 ++++++++++++++++++
 .../{wip.diff => transmission+apparmor.diff}  |   0
 shell.nix                                     |   4 +-
 11 files changed, 327 insertions(+), 110 deletions(-)
 delete mode 100644 nixos/modules/install/ssh-nixos.nix
 create mode 100644 nixpkgs/patches/installer.ssh-nixos.diff
 create mode 100644 nixpkgs/patches/security.pass.diff
 rename nixpkgs/patches/{wip.diff => transmission+apparmor.diff} (100%)

diff --git a/.envrc b/.envrc
index c147b99..30cb83a 100644
--- a/.envrc
+++ b/.envrc
@@ -2,7 +2,7 @@
 nix_version=2.3.6
 nix_openpgp=B541D55301270E0BCF15CA5D8170B4726D7198DE
 nixpkgs_channel=nixos-unstable-small
-nixshell_sources=".envrc shell.nix nodes.nix
+nixshell_sources=".envrc shell.nix machines.nix
  .config/nixpkgs-channel/$nixpkgs_channel.nix
  $(for d in shell nixpkgs; do
      test ! -d "$d" || find "$d" -type f -not -name "*~"
diff --git a/machines/losurdo.nix b/machines/losurdo.nix
index c932802..97df904 100644
--- a/machines/losurdo.nix
+++ b/machines/losurdo.nix
@@ -5,9 +5,9 @@
 # or:
 #  nix eval machines.losurdo.networking.hostName
 # Install/upgrade with:
-#   nix run config.install.ssh-nixos -f machines/losurdo.nix
+#   nix run config.installer.ssh-nixos -f machines/losurdo.nix
 # or:
-#   nix run machines.losurdo.install.ssh-nixos
+#   nix run machines.losurdo.installer.ssh-nixos
 {
 system = "x86_64-linux";
 extraArgs = {
diff --git a/machines/losurdo/security.nix b/machines/losurdo/security.nix
index a3d4e5e..5927bd2 100644
--- a/machines/losurdo/security.nix
+++ b/machines/losurdo/security.nix
@@ -22,15 +22,15 @@ security.pass = {
     '';
   };
 };
-install.ssh-nixos = {
+installer.ssh-nixos = {
   PATH = with pkgs; [gnupg openssh];
   # Decrypt the rootKey passphrase and the initrd SSH host key
   # and send them to the target host.
   script = lib.mkBefore ''
     gpg --decrypt '${pass.store}/${rootKey}.pass.gpg' |
-    ssh 'root@${config.install.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /${rootKey}.pass
+    ssh '${config.installer.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /${rootKey}.pass
     gpg --decrypt '${pass.store}/${initrdKey}.gpg' |
-    ssh 'root@${config.install.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /root/${initrdKey}
+    ssh '${config.installer.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /root/${initrdKey}
   '';
 };
 boot.initrd.network.ssh.hostKeys = [ "/root/${initrdKey}" ];
diff --git a/machines/mermet.nix b/machines/mermet.nix
index 9ce11e5..c8a9820 100644
--- a/machines/mermet.nix
+++ b/machines/mermet.nix
@@ -5,9 +5,9 @@
 # or:
 #  nix eval machines.mermet.networking.hostName
 # Install/upgrade with:
-#   nix run config.install.ssh-nixos -f machines/mermet.nix
+#   nix run config.installer.ssh-nixos -f machines/mermet.nix
 # or:
-#   nix run machines.mermet.install.ssh-nixos
+#   nix run machines.mermet.installer.ssh-nixos
 {
 system = "x86_64-linux";
 extraArgs = {
diff --git a/machines/mermet/security.nix b/machines/mermet/security.nix
index 28bd18d..ad9c83a 100644
--- a/machines/mermet/security.nix
+++ b/machines/mermet/security.nix
@@ -21,15 +21,15 @@ security.pass = {
     '';
   };
 };
-install.ssh-nixos = {
+installer.ssh-nixos = {
   PATH = with pkgs; [gnupg openssh];
   # Decrypt the rootKey passphrase and the initrd SSH host key
   # and send them to the target host.
   script = lib.mkBefore ''
     gpg --decrypt '${pass.store}/${rootKey}.pass.gpg' |
-    ssh root@'${config.install.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /${rootKey}.pass
+    ssh '${config.installer.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /${rootKey}.pass
     gpg --decrypt '${pass.store}/${initrdKey}.gpg' |
-    ssh root@'${config.install.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /root/${initrdKey}
+    ssh '${config.installer.ssh-nixos.target}' install -D -m 400 -o root -g root /dev/stdin /root/${initrdKey}
   '';
 };
 boot.initrd.network.ssh.hostKeys = [ "/root/${initrdKey}" ];
diff --git a/nixos/modules.nix b/nixos/modules.nix
index 0510481..eed873b 100644
--- a/nixos/modules.nix
+++ b/nixos/modules.nix
@@ -3,8 +3,6 @@
 # its clearer, safer and more flexible if not quicker.
 {
 imports = [
-  modules/install/ssh-nixos.nix
-  modules/security/pass.nix
   modules/services/networking/domains.nix
   modules/services/databases/openldap.nix
   modules/services/mail/public-inbox.nix
diff --git a/nixos/modules/install/ssh-nixos.nix b/nixos/modules/install/ssh-nixos.nix
deleted file mode 100644
index 3232f24..0000000
--- a/nixos/modules/install/ssh-nixos.nix
+++ /dev/null
@@ -1,96 +0,0 @@
-{ pkgs, lib, config, ... }:
-let
-  inherit (lib) types;
-  inherit (config) networking;
-  cfg = config.install.ssh-nixos;
-  nixRunDefaultCommand = "bash";
-in
-{
-options.install.ssh-nixos = {
-  PATH = lib.mkOption {
-    type = types.listOf types.package;
-    default = [];
-    apply = lib.makeBinPath;
-    description = "Packages to be added to the <literal>PATH<literal> of the install script.";
-  };
-  script = lib.mkOption {
-    type = types.lines;
-    default = "";
-    example = ''
-      lib.mkBefore ''''''
-        gpg --decrypt initrd/ssh.key.gpg |
-        ssh root@''${config.install.ssh-nixos.target} \
-        install -D -m 400 -o root -g root /dev/stdin /root/initrd/ssh.key
-      '''''';
-    '';
-    description = ''
-      Install script copying the configured NixOS to the <link linkend="opt-install.ssh-nixos.target">target</link>
-      and switching to the new configuration.
-      It is made available here for prepending or appending commands
-      with the usual <literal>mkBefore</literal> and <literal>mkAfter</literal>.
-      In case you run it often or add multiple ssh calls to it,
-      consider configuring the OpenSSH client with <literal>ControlMaster auto</literal>
-      to keep the SSH connexion alive between calls to <literal>literal</literal>.
-
-      This script is usually run with:
-      <screen>
-      <prompt>$ </prompt> nix run system.config.install.ssh-nixos -f nixos.nix
-      </screen>
-      where <literal>nixos.nix</literal> can be:
-      <screen>
-      import <nixpkgs/nixos> {
-        system = "x86_64-linux";
-        configuration = { config, lib, pkgs }: {
-        # Your usual configuration.nix content can go here
-        };
-      }
-      </screen>
-    '';
-    apply = script: pkgs.writeShellScriptBin nixRunDefaultCommand ''
-      set -eu
-      set -o pipefail
-      PATH="$PATH:${cfg.PATH}"
-      set -x
-      ${script}
-    '';
-  };
-  target = lib.mkOption {
-    type = types.str;
-    default = "${networking.hostName}.${networking.domain}";
-    example = "192.168.1.10";
-    description = "Destination where to install NixOS by SSH.";
-  };
-  sshFlags = lib.mkOption {
-    type = types.listOf types.str;
-    default = ["--substitute-on-destination"];
-    description = ''
-      Extra flags passed to <literal>ssh</literal>.
-      Environment variable <literal>SSH_FLAGS</literal> can also be used at runtime.
-    '';
-  };
-  nixCopyFlags = lib.mkOption {
-    type = types.listOf types.str;
-    default = ["--substitute-on-destination"];
-    description = ''
-      Extra flags passed to <literal>nix copy</literal>.
-      Environment variable <literal>SSH_FLAGS</literal> can also be used at runtime.
-    '';
-  };
-  profile = lib.mkOption {
-    type = types.str;
-    default = "/nix/var/nix/profiles/system";
-  };
-};
-config = {
-  install.ssh-nixos.PATH = with pkgs; [nix openssh];
-  install.ssh-nixos.script =
-    let nixos = config.system.build.toplevel; in ''
-    nix ''${NIX_FLAGS:-} copy \
-     --to ssh://root@${cfg.target} ${lib.concatStringsSep " " cfg.nixCopyFlags} ''${NIX_COPY_FLAGS:-} \
-     ${nixos}
-    ssh ''${SSH_FLAGS:-} 'root@${cfg.target}' nix-env --profile '${cfg.profile}' --set '${nixos}' \
-     '&&' '${cfg.profile}'/bin/switch-to-configuration "''${NIXOS_SWITCH:-switch}"
-  '';
-};
-meta.maintainers = [ lib.maintainers.julm ];
-}
diff --git a/nixpkgs/patches/installer.ssh-nixos.diff b/nixpkgs/patches/installer.ssh-nixos.diff
new file mode 100644
index 0000000..d73503c
--- /dev/null
+++ b/nixpkgs/patches/installer.ssh-nixos.diff
@@ -0,0 +1,130 @@
+diff --git a/nixos/modules/installer/ssh-nixos.nix b/nixos/modules/installer/ssh-nixos.nix
+new file mode 100644
+index 00000000000..52ac88799ee
+--- /dev/null
++++ b/nixos/modules/installer/ssh-nixos.nix
+@@ -0,0 +1,112 @@
++{ pkgs, lib, config, ... }:
++let
++  inherit (lib) types;
++  inherit (config) networking;
++  cfg = config.installer.ssh-nixos;
++  nixRunDefaultCommand = "bash";
++  ssh = pkgs.writeShellScriptBin "ssh" ''
++    set -eu
++    PATH=$OLDPATH
++    set -x
++    ssh -l '${cfg.login}' \
++     ${lib.escapeShellArgs cfg.sshFlags} ''${SSH_FLAGS:-} "$@"
++  '';
++in
++{
++options.installer.ssh-nixos = {
++  PATH = lib.mkOption {
++    type = types.listOf types.package;
++    default = [];
++    apply = lib.makeBinPath;
++    description = "Packages to be appended to the <literal>PATH<literal> of the script.";
++  };
++  script = lib.mkOption {
++    type = types.lines;
++    default = "";
++    example = ''
++      lib.mkBefore ''''''
++        gpg --decrypt initrd/ssh.key.gpg |
++        ssh root@''${config.installer.ssh-nixos.target} \
++        install -D -m 400 -o root -g root /dev/stdin /root/initrd/ssh.key
++      '''''';
++    '';
++    description = ''
++      Install script copying the configured NixOS to the <link linkend="opt-install.ssh-nixos.target">target</link>
++      and switching to the new configuration.
++      It is made available here for prepending or appending commands
++      with the usual <literal>mkBefore</literal> and <literal>mkAfter</literal>.
++      In case you run it often or add multiple ssh calls to it,
++      consider configuring the OpenSSH client with <literal>ControlMaster auto</literal>
++      to keep the SSH connexion alive between calls to <literal>literal</literal>.
++
++      This script is usually run with:
++      <screen>
++      <prompt>$ </prompt> nix run system.config.installer.ssh-nixos -f nixos.nix
++      </screen>
++      where <literal>nixos.nix</literal> can be:
++      <screen>
++      import <nixpkgs/nixos> {
++        system = "x86_64-linux";
++        configuration = { config, lib, pkgs }: {
++        # Your usual configuration.nix content can go here
++        };
++      }
++      </screen>
++    '';
++    apply = script: pkgs.writeShellScriptBin nixRunDefaultCommand ''
++      set -eu
++      set -o pipefail
++      export OLDPATH=$PATH:${cfg.PATH}
++      PATH="${ssh}/bin:$OLDPATH"
++      set -x
++      ${script}
++    '';
++  };
++  login = lib.mkOption {
++    type = types.str;
++    default = "root";
++    example = "admin";
++    description = "Login name passed to ssh.";
++  };
++  target = lib.mkOption {
++    type = types.str;
++    default = "${networking.hostName}.${networking.domain}";
++    example = "192.168.1.10";
++    description = "Destination where to install NixOS passed to ssh.";
++  };
++  sshFlags = lib.mkOption {
++    type = types.listOf types.str;
++    default = ["-o" "ControlMaster=auto"];
++    description = ''
++      Extra flags passed to <literal>ssh</literal>.
++      Environment variable <literal>SSH_FLAGS</literal> can also be used at runtime.
++    '';
++  };
++  nixCopyFlags = lib.mkOption {
++    type = types.listOf types.str;
++    default = ["--substitute-on-destination"];
++    description = ''
++      Extra flags passed to <literal>nix copy</literal>.
++      Environment variable <literal>NIX_COPY_FLAGS</literal> can also be used at runtime.
++    '';
++  };
++  profile = lib.mkOption {
++    type = types.str;
++    default = "/nix/var/nix/profiles/system";
++  };
++};
++config = {
++  installer.ssh-nixos.PATH = with pkgs; [nix openssh];
++  installer.ssh-nixos.script =
++    let nixos = config.system.build.toplevel; in ''
++    nix ''${NIX_FLAGS:-} copy \
++     --to ssh://'${cfg.target}' \
++     ${lib.escapeShellArgs cfg.nixCopyFlags} ''${NIX_COPY_FLAGS:-} \
++     ${nixos}
++    ssh '${cfg.target}' \
++    nix-env --profile '${cfg.profile}' --set '${nixos}' '&&' \
++    '${cfg.profile}'/bin/switch-to-configuration "''${NIXOS_SWITCH:-switch}"
++  '';
++};
++meta.maintainers = [ lib.maintainers.julm ];
++}
+diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
+index f361163ca63..15659fde11b 100644
+--- a/nixos/modules/module-list.nix
++++ b/nixos/modules/module-list.nix
+@@ -80,6 +80,7 @@
+   ./i18n/input-method/ibus.nix
+   ./i18n/input-method/nabi.nix
+   ./i18n/input-method/uim.nix
++  ./installer/ssh-nixos.nix
+   ./installer/tools/tools.nix
+   ./misc/assertions.nix
+   ./misc/crashdump.nix
diff --git a/nixpkgs/patches/security.pass.diff b/nixpkgs/patches/security.pass.diff
new file mode 100644
index 0000000..862b2c1
--- /dev/null
+++ b/nixpkgs/patches/security.pass.diff
@@ -0,0 +1,183 @@
+diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
+index f361163ca63..5e306de7dad 100644
+--- a/nixos/modules/module-list.nix
++++ b/nixos/modules/module-list.nix
+@@ -193,6 +193,7 @@
+   ./security/lock-kernel-modules.nix
+   ./security/misc.nix
+   ./security/oath.nix
++  ./security/pass.nix
+   ./security/pam.nix
+   ./security/pam_usb.nix
+   ./security/pam_mount.nix
+diff --git a/nixos/modules/security/pass.nix b/nixos/modules/security/pass.nix
+new file mode 100644
+index 00000000000..a2141d56d16
+--- /dev/null
++++ b/nixos/modules/security/pass.nix
+@@ -0,0 +1,165 @@
++{ pkgs, lib, config, ... }:
++let
++  inherit (builtins) dirOf head listToAttrs match split;
++  inherit (lib) types;
++  inherit (config.security) pass;
++  escapeUnitName = name:
++    lib.concatMapStrings (s: if lib.isList s then "-" else s)
++    (split "[^a-zA-Z0-9_.\\-]+" name);
++in
++{
++options.security.pass = {
++  store = lib.mkOption {
++    type = types.path;
++    description = ''
++      Default path to the password-store of the orchestrating system.
++    '';
++    # Does not copy the entire password-store into the Nix store,
++    # only the keys actually used will be.
++    apply = toString;
++  };
++  secrets = lib.mkOption {
++    default = {};
++    type = types.attrsOf (types.submodule ({name, config, ...}: {
++      options = {
++        gpg = lib.mkOption {
++          type = types.path;
++          default = builtins.path {
++            path = pass.store + "/${name}.gpg";
++            name = "${escapeUnitName name}.gpg";
++          };
++          description = ''
++            The path to the gnupg-encrypted secret.
++            It will be copied into the Nix store of the orchestrating and of the target system.
++            It must be decipherable by an OpenPGP key within <literal>gnupgHome</literal>,
++            whose passhrase is on the target system into <literal>passphraseFile</literal>.
++            Defaults to the name of the secret, prefixed by <literal>passwordStore</literal>
++            and suffixed by <literal>.gpg</literal>.
++          '';
++        };
++        gnupgHome = lib.mkOption {
++          type = types.str;
++          default = "/root/.gnupg";
++          description = ''
++            The directory on the target system to the <literal>gnupg</literal> home
++            used to decrypt the secret.
++          '';
++        };
++        passphraseFile = lib.mkOption {
++          type = types.str;
++          default = "/root/key.pass";
++          description = ''
++            The directory on the target system to a file containing
++            the password of an OpenPGP key in <literal>gnupgHome</literal>,
++            to which <literal>gpg</literal> secret is encrypted to.
++          '';
++        };
++        mode = lib.mkOption {
++          type = types.str;
++          default = "400";
++          description = ''
++            Permission mode of the secret <literal>path</literal>.
++          '';
++        };
++        user = lib.mkOption {
++          type = types.str;
++          default = "root";
++          description = ''
++            Owner of the secret <literal>path</literal>.
++          '';
++        };
++        group = lib.mkOption {
++          type = types.str;
++          default = "root";
++          description = ''
++            Group of the secret <literal>path</literal>.
++          '';
++        };
++        pipe = lib.mkOption {
++          type = types.nullOr types.str;
++          default = null;
++          description = ''
++            Shell command taking the deciphered secret on its standard input
++            and which must put on its standard output
++            the actual material to be installed.
++            This allows to decorate the secret with non-secret bits.
++          '';
++        };
++        path = lib.mkOption {
++          type = types.str;
++          default = name;
++          apply = p: if match "^/.*" p == null then "/run/pass-secrets/"+p+"/file" else p;
++          description = ''
++            The path on the target system where the secret is installed to.
++            Any non-absolute path is relative to <filename>/run/pass-secrets</filename>.
++            Default to the name of the secret.
++          '';
++        };
++        service = lib.mkOption {
++          type = types.str;
++          default = "secret-" + escapeUnitName name + ".service";
++          description = ''
++            The name of the systemd service.
++            Useful to put constraints like <literal>after</literal> or <literal>wants</wants>
++            into services requiring this secret.
++          '';
++        };
++        postStart = lib.mkOption {
++          type = types.lines;
++          default = "";
++          example = "systemctl reload nginx.service";
++          description = ''
++            Commands to run after new secrets go live. Typically
++            the web server and other servers using secrets need to
++            be reloaded.
++          '';
++        };
++      };
++    }));
++  };
++};
++config = lib.mkIf (pass.secrets != {}) {
++  systemd.services =
++    lib.mapAttrs' (target: secret:
++      lib.nameValuePair (lib.removeSuffix ".service" secret.service) {
++        description = "Install secret ${secret.path}";
++        script = ''
++          set -o pipefail
++          set -eux
++          decrypt() {
++            {
++            ${pkgs.gnupg}/bin/gpg --batch --pinentry-mode loopback \
++             --passphrase-file '${secret.passphraseFile}' \
++             --decrypt '${secret.gpg}' \
++            ${lib.optionalString (secret.pipe != null) (" | "+secret.pipe)}
++            } |
++            install -D -m '${secret.mode}' -o '${secret.user}' -g '${secret.group}' /dev/stdin \
++             '${secret.path}'
++          }
++          while ! decrypt; do sleep $((1 + ($RANDOM % 10))); done
++        '';
++        postStart = lib.optionalString (secret.postStart != "") ''
++          set -eux
++          ${secret.postStart}
++        '';
++        restartIfChanged = true;
++        restartTriggers = [
++          secret.passphraseFile
++          secret.gpg
++        ];
++        serviceConfig = {
++          Type = "oneshot";
++          Environment = "GNUPGHOME=${secret.gnupgHome}";
++          PrivateTmp = true;
++          RemainAfterExit = true;
++          WorkingDirectory = dirOf secret.gnupgHome;
++        } // lib.optionalAttrs (match "^/.*" target == null) {
++          RuntimeDirectory = lib.removePrefix "/run/" (dirOf secret.path);
++          RuntimeDirectoryMode = "711";
++          RuntimeDirectoryPreserve = false;
++        };
++      }
++    ) pass.secrets;
++};
++meta.maintainers = with lib.maintainers; [ julm ];
++}
diff --git a/nixpkgs/patches/wip.diff b/nixpkgs/patches/transmission+apparmor.diff
similarity index 100%
rename from nixpkgs/patches/wip.diff
rename to nixpkgs/patches/transmission+apparmor.diff
diff --git a/shell.nix b/shell.nix
index 10ca368..49e6b73 100644
--- a/shell.nix
+++ b/shell.nix
@@ -36,7 +36,9 @@ let
   ];
   localNixpkgsPatches = [
     #/home/julm/src/nix/nixpkgs/wip.patch
-    nixpkgs/patches/wip.diff
+    nixpkgs/patches/transmission+apparmor.diff
+    nixpkgs/patches/installer.ssh-nixos.diff
+    nixpkgs/patches/security.pass.diff
   ];
   # Build nixpkgs with some patches.
   nixpkgs = originPkgs.applyPatches {
-- 
2.47.2