From 4f9cea70bd75b812ccd7edc4e23e95da08eb3d9b Mon Sep 17 00:00:00 2001
From: Aaron Andersen <aaron@fosslib.net>
Date: Thu, 30 Jan 2020 21:15:56 -0500
Subject: [PATCH 1/3] nixos/duosec: fix indentation

---
 nixos/modules/security/duosec.nix | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index c686a6861d0f..2d5596738ce5 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -195,21 +195,21 @@ in
   };
 
   config = mkIf (cfg.ssh.enable || cfg.pam.enable) {
-     environment.systemPackages = [ pkgs.duo-unix ];
+    environment.systemPackages = [ pkgs.duo-unix ];
 
-     security.wrappers.login_duo.source = "${pkgs.duo-unix.out}/bin/login_duo";
-     environment.etc = loginCfgFile // pamCfgFile;
+    security.wrappers.login_duo.source = "${pkgs.duo-unix.out}/bin/login_duo";
+    environment.etc = loginCfgFile // pamCfgFile;
 
-     /* If PAM *and* SSH are enabled, then don't do anything special.
-     If PAM isn't used, set the default SSH-only options. */
-     services.openssh.extraConfig = mkIf (cfg.ssh.enable || cfg.pam.enable) (
-     if cfg.pam.enable then "UseDNS no" else ''
-       # Duo Security configuration
-       ForceCommand ${config.security.wrapperDir}/login_duo
-       PermitTunnel no
-       ${optionalString (!cfg.allowTcpForwarding) ''
-         AllowTcpForwarding no
-       ''}
-     '');
+    /* If PAM *and* SSH are enabled, then don't do anything special.
+    If PAM isn't used, set the default SSH-only options. */
+    services.openssh.extraConfig = mkIf (cfg.ssh.enable || cfg.pam.enable) (
+    if cfg.pam.enable then "UseDNS no" else ''
+      # Duo Security configuration
+      ForceCommand ${config.security.wrapperDir}/login_duo
+      PermitTunnel no
+      ${optionalString (!cfg.allowTcpForwarding) ''
+        AllowTcpForwarding no
+      ''}
+    '');
   };
 }

From b9dca769f150483b2e5e01c41c7df1e44f48f996 Mon Sep 17 00:00:00 2001
From: Aaron Andersen <aaron@fosslib.net>
Date: Thu, 30 Jan 2020 21:18:43 -0500
Subject: [PATCH 2/3] nixos/duosec: replace insecure skey option with secure
 secretKeyFile option

---
 nixos/doc/manual/release-notes/rl-2009.xml |  8 +++
 nixos/modules/security/duosec.nix          | 61 ++++++++++++++--------
 2 files changed, 48 insertions(+), 21 deletions(-)

diff --git a/nixos/doc/manual/release-notes/rl-2009.xml b/nixos/doc/manual/release-notes/rl-2009.xml
index 2f61ee5ae2ed..1ca172c99f13 100644
--- a/nixos/doc/manual/release-notes/rl-2009.xml
+++ b/nixos/doc/manual/release-notes/rl-2009.xml
@@ -96,6 +96,14 @@
       <option>systemd.services.supybot.serviceConfig</option>.
     </para>
    </listitem>
+   <listitem>
+    <para>
+      The <literal>security.duosec.skey</literal> option, which stored a secret in the
+      nix store, has been replaced by a new
+      <link linkend="opt-security.duosec.secretKeyFile">security.duosec.secretKeyFile</link>
+      option for better security.
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index 2d5596738ce5..38169706463d 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -10,7 +10,6 @@ let
   configFilePam = ''
     [duo]
     ikey=${cfg.ikey}
-    skey=${cfg.skey}
     host=${cfg.host}
     ${optionalString (cfg.groups != "") ("groups="+cfg.groups)}
     failmode=${cfg.failmode}
@@ -24,26 +23,11 @@ let
     motd=${boolToStr cfg.motd}
     accept_env_factor=${boolToStr cfg.acceptEnvFactor}
   '';
-
-  loginCfgFile = optionalAttrs cfg.ssh.enable {
-    "duo/login_duo.conf" =
-      { source = pkgs.writeText "login_duo.conf" configFileLogin;
-        mode   = "0600";
-        user   = "sshd";
-      };
-  };
-
-  pamCfgFile = optional cfg.pam.enable {
-    "duo/pam_duo.conf" =
-      { source = pkgs.writeText "pam_duo.conf" configFilePam;
-        mode   = "0600";
-        user   = "sshd";
-      };
-  };
 in
 {
   imports = [
     (mkRenamedOptionModule [ "security" "duosec" "group" ] [ "security" "duosec" "groups" ])
+    (mkRemovedOptionModule [ "security" "duosec" "skey" ] "The insecure security.duosec.skey option has been replaced by a new security.duosec.secretKeyFile option. Use this new option to store a secure copy of your key instead.")
   ];
 
   options = {
@@ -65,9 +49,13 @@ in
         description = "Integration key.";
       };
 
-      skey = mkOption {
-        type = types.str;
-        description = "Secret key.";
+      secretKeyFile = mkOption {
+        type = types.path;
+        default = null;
+        description = ''
+          A file containing your secret key. The security of your Duo application is tied to the security of your secret key.
+        '';
+        example = "/run/keys/duo-skey";
       };
 
       host = mkOption {
@@ -198,7 +186,38 @@ in
     environment.systemPackages = [ pkgs.duo-unix ];
 
     security.wrappers.login_duo.source = "${pkgs.duo-unix.out}/bin/login_duo";
-    environment.etc = loginCfgFile // pamCfgFile;
+
+    system.activationScripts = {
+      login_duo = mkIf cfg.ssh.enable ''
+        if test -f "${cfg.secretKeyFile}"; then
+          mkdir -m 0755 -p /etc/duo
+
+          umask 0077
+          conf="$(mktemp)"
+          {
+            cat ${pkgs.writeText "login_duo.conf" configFileLogin}
+            printf 'skey = %s\n' "$(cat ${cfg.secretKeyFile})"
+          } >"$conf"
+
+          chown sshd "$conf"
+          mv -fT "$conf" /etc/duo/login_duo.conf
+        fi
+      '';
+      pam_duo = mkIf cfg.pam.enable ''
+        if test -f "${cfg.secretKeyFile}"; then
+          mkdir -m 0755 -p /etc/duo
+
+          umask 0077
+          conf="$(mktemp)"
+          {
+            cat ${pkgs.writeText "login_duo.conf" configFilePam}
+            printf 'skey = %s\n' "$(cat ${cfg.secretKeyFile})"
+          } >"$conf"
+
+          mv -fT "$conf" /etc/duo/pam_duo.conf
+        fi
+      '';
+    };
 
     /* If PAM *and* SSH are enabled, then don't do anything special.
     If PAM isn't used, set the default SSH-only options. */

From 6f0c1cdbd9ff567ca8d723bbe2bb560145300cb3 Mon Sep 17 00:00:00 2001
From: Aaron Andersen <aaron@fosslib.net>
Date: Thu, 30 Jan 2020 21:21:47 -0500
Subject: [PATCH 3/3] nixos/duosec: rename ikey option to integrationKey

---
 nixos/doc/manual/release-notes/rl-2009.xml | 4 ++++
 nixos/modules/security/duosec.nix          | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/nixos/doc/manual/release-notes/rl-2009.xml b/nixos/doc/manual/release-notes/rl-2009.xml
index 1ca172c99f13..a9a6003d1e8a 100644
--- a/nixos/doc/manual/release-notes/rl-2009.xml
+++ b/nixos/doc/manual/release-notes/rl-2009.xml
@@ -103,6 +103,10 @@
       <link linkend="opt-security.duosec.secretKeyFile">security.duosec.secretKeyFile</link>
       option for better security.
     </para>
+    <para>
+      <literal>security.duosec.ikey</literal> has been renamed to
+      <link linkend="opt-security.duosec.integrationKey">security.duosec.integrationKey</link>.
+    </para>
    </listitem>
   </itemizedlist>
  </section>
diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index 38169706463d..71428b82f5da 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -9,7 +9,7 @@ let
 
   configFilePam = ''
     [duo]
-    ikey=${cfg.ikey}
+    ikey=${cfg.integrationKey}
     host=${cfg.host}
     ${optionalString (cfg.groups != "") ("groups="+cfg.groups)}
     failmode=${cfg.failmode}
@@ -27,6 +27,7 @@ in
 {
   imports = [
     (mkRenamedOptionModule [ "security" "duosec" "group" ] [ "security" "duosec" "groups" ])
+    (mkRenamedOptionModule [ "security" "duosec" "ikey" ] [ "security" "duosec" "integrationKey" ])
     (mkRemovedOptionModule [ "security" "duosec" "skey" ] "The insecure security.duosec.skey option has been replaced by a new security.duosec.secretKeyFile option. Use this new option to store a secure copy of your key instead.")
   ];
 
@@ -44,7 +45,7 @@ in
         description = "If enabled, protect logins with Duo Security using PAM support.";
       };
 
-      ikey = mkOption {
+      integrationKey = mkOption {
         type = types.str;
         description = "Integration key.";
       };