diff --git a/morph/README.rst b/morph/README.rst
index 7f8bb655b36010ae2bcb152632b39387de0a412e..d4a89a373a1bef767ad26859d495f1528a4fb7ca 100644
--- a/morph/README.rst
+++ b/morph/README.rst
@@ -3,10 +3,35 @@ Morph
 
 This directory contains Nix-based configuration for the grid.
 This takes the form of Nix expressions in ``.nix`` files
-and some JSON-based configuration in ``.config.json`` files.
+and some JSON-based configuration in ``.json`` files.
 
 This configuration is fed to `morph`_ to make changes to the deployment.
 
+Deploying
+`````````
+
+The deployment consists of the public software packages and the private secrets.
+You can deploy these together::
+
+  morph deploy --upload-secrets morph/grid/<testing|production|...>/grid.nix test
+
+Or separately::
+
+  morph deploy morph/grid/<testing|production|...>/grid.nix test
+  morph upload-secrets morph/grid/<testing|production|...>/grid.nix
+
+Separate deployment is useful when the software deploy is done from system which may not be sufficiently secure to host the secrets
+(such as a cloud build machine).
+Secrets should only be hosted on an extremely secure system
+(XXX write the document for what this means).
+
+Note secrets only need to be uploaded after a host in the grid has been rebooted or when the secrets have changed.
+
+See the ``morph`` and ``nixos-rebuild`` documentation for more details about these commands.
+
+Filesystem Layout
+`````````````````
+
 lib
 ---
 
@@ -49,7 +74,7 @@ Each such file contains a minimal Nix expression supplying critical system confi
 These files are referenced by the corresponding ``<hostname>.nix`` files.
 
 Configuring New Storage Nodes
------------------------------
+`````````````````````````````
 
 Storage nodes are brought into the grid in a multi-step process.
 Here are the steps to configure a new node,
diff --git a/morph/grid/production/grid.nix b/morph/grid/production/grid.nix
index a65b77bd9a873c659ee9bb9f6f16aac4c2d45d6d..7b056146c300952f014da6fc57e71ee022ac58a5 100644
--- a/morph/grid/production/grid.nix
+++ b/morph/grid/production/grid.nix
@@ -4,7 +4,10 @@
 import ../../lib/make-grid.nix {
   name = "Production";
   config = ./config.json;
-  nodes = cfg: {
+  nodes = cfg:
+    let
+      sshUsers = import ../../../../PrivateStorageSecrets/production-users.nix;
+    in {
     # Here are the hosts that are in this morph network.  This is sort of like
     # a server manifest.  We try to keep as many of the specific details as
     # possible out of *this* file so that this file only grows as server count
@@ -18,32 +21,38 @@ import ../../lib/make-grid.nix {
     #
     # The names must be unique!
     "payments.privatestorage.io" = import ../../lib/issuer.nix ({
+      inherit sshUsers;
       hardware = ../../lib/issuer-aws.nix;
       stateVersion = "19.03";
     } // cfg);
 
     "storage001" = import ../../lib/make-storage.nix ({
         cfg = import ./storage001-config.nix;
+        inherit sshUsers;
         hardware = ./storage001-hardware.nix;
         stateVersion = "19.09";
     } // cfg);
     "storage002" = import ../../lib/make-storage.nix ({
         cfg = import ./storage002-config.nix;
+        inherit sshUsers;
         hardware = ./storage002-hardware.nix;
         stateVersion = "19.09";
     } // cfg);
     "storage003" = import ../../lib/make-storage.nix ({
         cfg = import ./storage003-config.nix;
+        inherit sshUsers;
         hardware = ./storage003-hardware.nix;
         stateVersion = "19.09";
     } // cfg);
     "storage004" = import ../../lib/make-storage.nix ({
         cfg = import ./storage004-config.nix;
+        inherit sshUsers;
         hardware = ./storage004-hardware.nix;
         stateVersion = "19.09";
     } // cfg);
     "storage005" = import ../../lib/make-storage.nix ({
         cfg = import ./storage005-config.nix;
+        inherit sshUsers;
         hardware = ./storage005-hardware.nix;
         stateVersion = "19.03";
     } // cfg);
diff --git a/morph/grid/production/storage000-config.nix b/morph/grid/production/storage000-config.nix
index b1d38ecb1f896b740f0a392df14da670d0156a48..2a056a5489245e7e334a26fd9b784097512f6196 100644
--- a/morph/grid/production/storage000-config.nix
+++ b/morph/grid/production/storage000-config.nix
@@ -4,5 +4,4 @@
   "gateway" = "69.36.183.1";
   "gatewayInterface" = "eno1";
   "grubDeviceID" = "wwn-0x5000c500936410b9";
-  "rootPublicKey" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4GenAY/YLGuf1WoMXyyVa3S9i4JLQ0AG+pt7nvcLlQ exarkun@baryon";
 }
diff --git a/morph/grid/production/storage001-config.nix b/morph/grid/production/storage001-config.nix
index 2e6e21548c978f8d41e5856af03caa64124864de..63b0e876c32995e10e24e7afa5b9aa9c41025b51 100644
--- a/morph/grid/production/storage001-config.nix
+++ b/morph/grid/production/storage001-config.nix
@@ -5,5 +5,4 @@
   "gateway" = "176.113.72.37";
   "gatewayInterface" = "eno1";
   "grubDeviceID" = "wwn-0x5000cca25cc08d27";
-  "rootPublicKey" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4GenAY/YLGuf1WoMXyyVa3S9i4JLQ0AG+pt7nvcLlQ exarkun@baryon";
 }
diff --git a/morph/grid/production/storage002-config.nix b/morph/grid/production/storage002-config.nix
index c9ddf1779d13d5fe67f03088007fcb11085b8bd7..d74a99ec1824d798564cd4c469684af1dcf989d4 100644
--- a/morph/grid/production/storage002-config.nix
+++ b/morph/grid/production/storage002-config.nix
@@ -5,5 +5,4 @@
   "gateway" = "37.120.214.109";
   "gatewayInterface" = "eno1";
   "grubDeviceID" = "wwn-0x5000cca25dccb3dc";
-  "rootPublicKey" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4GenAY/YLGuf1WoMXyyVa3S9i4JLQ0AG+pt7nvcLlQ exarkun@baryon";
 }
diff --git a/morph/grid/production/storage003-config.nix b/morph/grid/production/storage003-config.nix
index 2feb5eec1460913d1c4ed049cee4c52c50bbbb4c..e83546adbcdab2fd35d990a13550dd3907d7226b 100644
--- a/morph/grid/production/storage003-config.nix
+++ b/morph/grid/production/storage003-config.nix
@@ -5,5 +5,4 @@
   "gateway" = "45.83.89.185";
   "gatewayInterface" = "eno1";
   "grubDeviceID" = "wwn-0x5000cca248c31469";
-  "rootPublicKey" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4GenAY/YLGuf1WoMXyyVa3S9i4JLQ0AG+pt7nvcLlQ exarkun@baryon";
 }
diff --git a/morph/grid/production/storage004-config.nix b/morph/grid/production/storage004-config.nix
index 8143e30e39140c1fe3f4b5b76560562488b1c31f..8201391c433281092044a284fb5c15a9933929cb 100644
--- a/morph/grid/production/storage004-config.nix
+++ b/morph/grid/production/storage004-config.nix
@@ -5,5 +5,4 @@
   "gateway" = "87.101.93.197";
   "gatewayInterface" = "eno1";
   "grubDeviceID" = "wwn-0x5000cca249d45533";
-  "rootPublicKey" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4GenAY/YLGuf1WoMXyyVa3S9i4JLQ0AG+pt7nvcLlQ exarkun@baryon";
 }
diff --git a/morph/grid/production/storage005-config.nix b/morph/grid/production/storage005-config.nix
index 75eeece531b22fc84370a82e598128f672470616..42ac495af0064b52acdd0cbd287d84aba1f0bd0c 100644
--- a/morph/grid/production/storage005-config.nix
+++ b/morph/grid/production/storage005-config.nix
@@ -5,5 +5,4 @@
   "gateway" = "193.148.18.205";
   "gatewayInterface" = "eno1";
   "grubDeviceID" = "wwn-0x5000cca25dcc78b5";
-  "rootPublicKey" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4GenAY/YLGuf1WoMXyyVa3S9i4JLQ0AG+pt7nvcLlQ exarkun@baryon";
 }
diff --git a/morph/grid/testing/grid.nix b/morph/grid/testing/grid.nix
index 4db91363105ab9f35d21ccb037427cbfb7226003..3a1c5f3921c196843b0a4cd1b18f20388a75edde 100644
--- a/morph/grid/testing/grid.nix
+++ b/morph/grid/testing/grid.nix
@@ -4,14 +4,19 @@
 import ../../lib/make-grid.nix {
   name = "Testing";
   config = ./config.json;
-  nodes = cfg: {
+  nodes = cfg:
+  let
+    sshUsers = import ../../../../PrivateStorageSecrets/staging-users.nix;
+  in {
     "payments.privatestorage-staging.com" = import ../../lib/issuer.nix ({
+      inherit sshUsers;
       hardware = ../../lib/issuer-aws.nix;
       stateVersion = "19.03";
     } // cfg);
 
     "3.120.26.190" = import ../../lib/make-testing.nix (cfg // {
       publicIPv4 = "3.120.26.190";
+      inherit sshUsers;
       hardware = ./testing001-hardware.nix;
       stateVersion = "19.03";
     });
diff --git a/morph/lib/issuer.nix b/morph/lib/issuer.nix
index 6e1eca671b0774775cbecdeed55703c6e7b02ea1..33c87f70d81e0ad064977ab7204c5484f4d9e7e6 100644
--- a/morph/lib/issuer.nix
+++ b/morph/lib/issuer.nix
@@ -4,6 +4,7 @@
 , issuerDomain
 , letsEncryptAdminEmail
 , allowedChargeOrigins
+, sshUsers
 , stateVersion
 , ...
 }: {
@@ -33,6 +34,7 @@
     ../../nixos/modules/issuer.nix
   ];
 
+  services.private-storage.sshUsers = sshUsers;
   services.private-storage-issuer = {
     enable = true;
     tls = true;
diff --git a/morph/lib/make-storage.nix b/morph/lib/make-storage.nix
index da206572566b1b997d4160ba46a98aa4fd547430..0c556befc096f0fb8fa4476e6bad234e3e9231a2 100644
--- a/morph/lib/make-storage.nix
+++ b/morph/lib/make-storage.nix
@@ -3,6 +3,7 @@
 , hardware                   # The path to the hardware configuration for this node.
 , publicStoragePort          # The storage port number on which to accept connections.
 , ristrettoSigningKeyPath    # The *local* path to the Ristretto signing key file.
+, sshUsers                   # Users for which to configure SSH access to this node.
 , stateVersion               # The value for system.stateVersion on this node.
                              # This value determines the NixOS release with
                              # which your system is to be compatible, in order
@@ -56,6 +57,8 @@
     inherit publicStoragePort;
     # Give it the Ristretto signing key, too, to support authorization.
     ristrettoSigningKeyPath = deployment.secrets.ristretto-signing-key.destination;
+    # It gets the users, too.
+    inherit sshUsers;
   };
 
   system.stateVersion = stateVersion;
diff --git a/morph/lib/make-testing.nix b/morph/lib/make-testing.nix
index 24de7ea40ad778d0ca2418be063a4a1528965839..df8eb006b3234d5e127a334a401c9079d5adc2fb 100644
--- a/morph/lib/make-testing.nix
+++ b/morph/lib/make-testing.nix
@@ -1,4 +1,4 @@
-{ publicIPv4, hardware, publicStoragePort, ristrettoSigningKeyPath, stateVersion, ... }: rec {
+{ publicIPv4, hardware, publicStoragePort, ristrettoSigningKeyPath, sshUsers, stateVersion, ... }: rec {
 
   deployment = {
     secrets = {
@@ -26,6 +26,7 @@
     inherit publicIPv4;
     inherit publicStoragePort;
     ristrettoSigningKeyPath = deployment.secrets.ristretto-signing-key.destination;
+    inherit sshUsers;
   };
 
   system.stateVersion = stateVersion;
diff --git a/nixos/modules/100tb.nix b/nixos/modules/100tb.nix
index ec4bf66579d4d9b89065f02df3ee454f5b647294..1bcb6ba176714ca3cfa5c527450dd9a3bc60684d 100644
--- a/nixos/modules/100tb.nix
+++ b/nixos/modules/100tb.nix
@@ -69,11 +69,6 @@ let
       example = lib.literalExample "wwn-0x5000c500936410b9";
       description = "The ID of the disk on which to install grub.";
     };
-    rootPublicKey = lib.mkOption
-    { type = lib.types.str;
-      example = lib.literalExample "ssh-ed25519 AAAA... username@host";
-      description = "The public key to install for the root user.";
-    };
   };
 in {
   # Here we actually define the module's options.  They're what we said they
@@ -112,11 +107,6 @@ in {
 
     boot.loader.timeout = 1;
     networking.firewall.enable = false;
-    services.openssh.enable = true;
-
-    users.users.root.openssh.authorizedKeys.keys = [
-      cfg.rootPublicKey
-    ];
 
     networking.hostId = cfg.hostId;
     networking.dhcpcd.enable = false;
diff --git a/nixos/modules/issuer.nix b/nixos/modules/issuer.nix
index a65eed5a3539f2d5ba67870782635a1ae7209582..7654bf1fc7082afcdc2056a9373deea89bdc4f19 100644
--- a/nixos/modules/issuer.nix
+++ b/nixos/modules/issuer.nix
@@ -1,10 +1,15 @@
-# A NixOS module which can run a Ristretto-based issuer for PrivacyStorage
+# A NixOS module which can run a Ristretto-based issuer for PrivateStorage
 # ZKAPs.
 { lib, pkgs, config, ... }: let
   pspkgs = pkgs.callPackage ./pspkgs.nix { };
   zkapissuer = pspkgs.callPackage ../pkgs/zkapissuer.nix { };
   cfg = config.services.private-storage-issuer;
 in {
+  imports = [
+    # Give it a good SSH configuration.
+    ../../nixos/modules/ssh.nix
+  ];
+
   options = {
     services.private-storage-issuer.enable = lib.mkEnableOption "PrivateStorage ZKAP Issuer Service";
     services.private-storage-issuer.package = lib.mkOption {
diff --git a/nixos/modules/private-storage.nix b/nixos/modules/private-storage.nix
index 687c9e35d609601f85a57d2ac85c7aac7b66cbf9..cada491e04a49ce1e4931b58ffae6527f8cf77c5 100644
--- a/nixos/modules/private-storage.nix
+++ b/nixos/modules/private-storage.nix
@@ -29,10 +29,12 @@ in
   [ "services/network-filesystems/tahoe.nix"
   ];
 
-  # Load our tahoe-lafs module.  It is configurable in the way I want it to be
-  # configurable.
-  imports =
-  [ ./tahoe.nix
+  imports = [
+    # Give it a good SSH configuration.
+    ./ssh.nix
+    # Load our tahoe-lafs module.  It is configurable in the way I want it to
+    # be configurable.
+    ./tahoe.nix
   ];
 
   options =
diff --git a/nixos/modules/ssh.nix b/nixos/modules/ssh.nix
new file mode 100644
index 0000000000000000000000000000000000000000..59ee2fec949be247143041379626f35b7d8bf657
--- /dev/null
+++ b/nixos/modules/ssh.nix
@@ -0,0 +1,55 @@
+# A NixOS module which configures SSH access to a system.
+{
+  lib,
+  config,
+  ...
+}: {
+  options = {
+    services.private-storage.sshUsers = lib.mkOption {
+      type = lib.types.attrsOf lib.types.str;
+      example = lib.literalExample { root = "ssh-ed25519 AAA..."; };
+      description = ''
+        Users to configure on the issuer server and the storage servers and
+        the SSH public keys to use to authenticate them.
+      '';
+    };
+  };
+  config =
+  let
+     cfg = config.services."private-storage";
+  in {
+    # An attempt at a properly secure SSH configuration.  This is informed by
+    # personal experience as well as various web resources:
+    #
+    # https://www.cyberciti.biz/tips/linux-unix-bsd-openssh-server-best-practices.html
+    services.openssh = {
+      enable = true;
+
+      # We don't use SFTP for anything.  No reason to expose it.
+      allowSFTP = false;
+
+      # We only allow key-based authentication.
+      challengeResponseAuthentication = false;
+      passwordAuthentication = false;
+
+      extraConfig = ''
+        # Possibly this is superfluous considering we don't allow
+        # password-based authentication at all.
+        PermitEmptyPasswords no
+
+        # Only allow authentication as one of the configured users, not random
+        # other (often system-managed) users.  Possibly this is also
+        # superfluous!  NixOS system users have nologin as their shell ... so they
+        # cannot log in anyway.
+        AllowUsers ${builtins.concatStringsSep " " (builtins.attrNames cfg.sshUsers)}
+      '';
+    };
+
+    users.users =
+      let makeUserConfig = username: sshPublicKey: {
+        isNormalUser = username != "root";
+        openssh.authorizedKeys.keys = [ sshPublicKey ];
+      };
+      in builtins.mapAttrs makeUserConfig cfg.sshUsers;
+  };
+}
diff --git a/nixos/modules/tahoe.nix b/nixos/modules/tahoe.nix
index 05e68d4fd8c8bb83be85afefc6f1de66439cad8e..f1274534795fc53e27467ac9e28c34c6ae1e8be2 100644
--- a/nixos/modules/tahoe.nix
+++ b/nixos/modules/tahoe.nix
@@ -172,10 +172,10 @@ in
         #   (node: settings: settings.tub.port);
         systemd.services = flip mapAttrs' cfg.nodes (node: settings:
           let
-            pidfile = "/run/tahoe.${node}.pid";
+            pidfile = "/run/tahoe.${lib.escapeShellArg node}.pid";
             # This is a directory, but it has no trailing slash. Tahoe commands
             # get antsy when there's a trailing slash.
-            nodedir = "/var/db/tahoe-lafs/${node}";
+            nodedir = "/var/db/tahoe-lafs/${lib.escapeShellArg node}";
           in nameValuePair "tahoe.${node}" {
             description = "Tahoe LAFS node ${node}";
             wantedBy = [ "multi-user.target" ];
@@ -189,13 +189,31 @@ in
               # arguments to $(tahoe run). The node directory must come first,
               # and arguments which alter Twisted's behavior come afterwards.
               ExecStart = ''
-                ${settings.package}/bin/tahoe run ${lib.escapeShellArg nodedir} -n -l- --pidfile=${lib.escapeShellArg pidfile}
+                ${settings.package}/bin/tahoe run ${nodedir} -n -l- --pidfile=${pidfile}
               '';
             };
-            preStart = ''
-              if [ ! -d ${lib.escapeShellArg nodedir} ]; then
-                mkdir -p /var/db/tahoe-lafs
-                tahoe create-node --hostname=localhost ${lib.escapeShellArg nodedir}
+            preStart =
+            let
+              created = "${nodedir}.created";
+              atomic = "${nodedir}.atomic";
+            in ''
+              if [ ! -e ${created} ]; then
+                mkdir -p /var/db/tahoe-lafs/
+
+                # Get rid of any prior partial efforts.  It might not exist.
+                # Don't let this tank us.
+                rm -rv ${atomic} && [ ! -e ${atomic} ]
+
+                # Really create the node.
+                tahoe create-node --hostname=localhost ${atomic}
+
+                # Move it to the real location.  We don't create it in-place
+                # because we might fail partway through and leave inconsistent
+                # state.  Also, systemd probably created logs/incidents/ already and
+                # `create-node` complains if it finds these exist already.
+                rm -rv ${nodedir} && [ ! -e ${nodedir} ]
+                mv ${atomic} ${nodedir}
+                touch ${created}
               fi
 
               # Tahoe has created a predefined tahoe.cfg which we must now
@@ -204,7 +222,7 @@ in
               # we must do this on every prestart. Fixes welcome.
               # rm ${nodedir}/tahoe.cfg
               # ln -s /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${nodedir}/tahoe.cfg
-              cp /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${lib.escapeShellArg nodedir}/tahoe.cfg
+              cp /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${nodedir}/tahoe.cfg
             '';
           });
         users.users = flip mapAttrs' cfg.nodes (node: _:
diff --git a/nixos/modules/tests/get-passes.py b/nixos/modules/tests/get-passes.py
index 96875713233b7c46abae0cfc3f0d946628bf8cc2..39690ad8a41edd161c4ff1f6a682669c15828266 100755
--- a/nixos/modules/tests/get-passes.py
+++ b/nixos/modules/tests/get-passes.py
@@ -42,13 +42,23 @@ def main():
         response.raise_for_status()
 
     # Poll the vouchers list for a while to see it get redeemed.
-    expected = {"version": 1, "number": voucher, "redeemed": True}
     def find_redeemed_voucher():
         response = get(zkapauthz + "/voucher/" + voucher)
         response.raise_for_status()
         actual = response.json()
         print("Actual response: {}".format(actual))
-        return expected == actual
+        try:
+            check = (
+                actual["version"],
+                actual["number"],
+                actual["state"]["name"],
+            )
+        except Exception as e:
+            print("Check failed: {}".format(e))
+            return False
+        else:
+            print("Checking {}".format(check))
+            return check == (1, voucher, "redeemed")
 
     retry(
         "find redeemed voucher",
diff --git a/nixos/modules/tests/private-storage.nix b/nixos/modules/tests/private-storage.nix
index 1fe55c1302b35aeb9e5645bbc1cb60053fc6e97c..47acfbf475a5d029b5f2800d4a11e2ff18eaa9d2 100644
--- a/nixos/modules/tests/private-storage.nix
+++ b/nixos/modules/tests/private-storage.nix
@@ -2,6 +2,20 @@ let
   pkgs = import <nixpkgs> { };
   pspkgs = import ../pspkgs.nix { inherit pkgs; };
 
+  sshPrivateKey = ./probeuser_ed25519;
+  sshPublicKey = ./probeuser_ed25519.pub;
+  sshUsers = {
+    root = (builtins.readFile sshPublicKey);
+    probeuser = (builtins.readFile sshPublicKey);
+  };
+  # Generate a command which can be used with runOnNode to ssh to the given
+  # host.
+  ssh = username: hostname: [
+    "cp" sshPrivateKey "/tmp/ssh_key" ";"
+    "chmod" "0400" "/tmp/ssh_key" ";"
+    "ssh" "-oStrictHostKeyChecking=no" "-i" "/tmp/ssh_key" "${username}@${hostname}" ":"
+  ];
+
   # Separate helper programs so we can write as little perl inside a string
   # inside a nix expression as possible.
   run-introducer = ./run-introducer.py;
@@ -108,6 +122,8 @@ import <nixpkgs/nixos/tests/make-test.nix> {
           introducerFURL = introducerFURL;
           issuerRootURL = issuerURL;
           inherit ristrettoSigningKeyPath;
+          inherit sshUsers;
+
         };
       } // networkConfig;
 
@@ -117,6 +133,8 @@ import <nixpkgs/nixos/tests/make-test.nix> {
     { imports =
       [ ../issuer.nix
       ];
+      services.private-storage.sshUsers = sshUsers;
+
       services.private-storage-issuer = {
         enable = true;
         domain = "issuer";
@@ -165,6 +183,16 @@ import <nixpkgs/nixos/tests/make-test.nix> {
       # Start booting all the VMs in parallel to speed up operations down below.
       startAll;
 
+      # The issuer and the storage server should accept SSH connections.  This
+      # doesn't prove it is so but if it fails it's a pretty good indication
+      # it isn't so.
+      $storage->waitForOpenPort(22);
+      ${runOnNode "issuer" (ssh "probeuser" "storage")}
+      ${runOnNode "issuer" (ssh "root" "storage")}
+      $issuer->waitForOpenPort(22);
+      ${runOnNode "storage" (ssh "probeuser" "issuer")}
+      ${runOnNode "storage" (ssh "root" "issuer")}
+
       # Set up a Tahoe-LAFS introducer.
       $introducer->copyFileFromHost(
           '${pemFile}',
diff --git a/nixos/modules/tests/probeuser_ed25519 b/nixos/modules/tests/probeuser_ed25519
new file mode 100644
index 0000000000000000000000000000000000000000..09c734d087d2e550163f11c088f7262e8a4b0e8b
--- /dev/null
+++ b/nixos/modules/tests/probeuser_ed25519
@@ -0,0 +1,38 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+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
+-----END OPENSSH PRIVATE KEY-----
diff --git a/nixos/modules/tests/probeuser_ed25519.pub b/nixos/modules/tests/probeuser_ed25519.pub
new file mode 100644
index 0000000000000000000000000000000000000000..e9ba1bbd5cf64d7448845d1408846e201085be4d
--- /dev/null
+++ b/nixos/modules/tests/probeuser_ed25519.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD1GpUUiM4j1bDCGaWu3cch6ibh+Apx13oNby8VHblrKdcYgvAgUUn0FbUiGsQB1JR3C3B0MMoHWdXcPG9itLi23L4F1sqXxlurJ+UfLzuw2e3Tbsum8Fr0BF5mnt41dnibIhF6DuVCdB47JVZd8XvLY4LMFRvTz0g77YB2gUEOsOu+cmkNdRGIGmPygD0U693gHOR9G5KpM44NOuNdKKWENJTQ3mSSjlufLTu1YOwj6hskVUYAvM7mu3zojxP5utZ68DAD3kM9ADCsgrtyX0714f/n1xUFjB1Ay2AZ+OqxIds/ZirFE6OQr0EVICA2JvYhfInQ6TNk3Swh/b3aVSSQN8qml8nwj7PVZzfv8TwuRbQHkpLFqXv1x+1TGokhPWx95UOjfWvlR0rxX2SQC2wkU2omsRPIwNl5ugkXnHxhZcKBAz75Ozbg/e8FzA4nBy9qb4Fya1mFrLb7SOsEVWoDwyTDzM0RWIZpX/OUpJ+3dl61jKPmWT8ms2odKXlP2Pk= probeuser