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