From f9844a8080646b9ac9d4bf93cc871fea666bf96a Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Fri, 25 Jun 2021 14:21:14 -0400
Subject: [PATCH] Parameterize more things

---
 .gitlab-ci.yml                  | 18 +++++++++++++-
 ci-tools/deploy-to-staging      | 43 +++++++++++++++++++++++----------
 nixos/modules/deployment.nix    | 28 +++++++++++++++++++--
 nixos/modules/update-deployment |  4 ++-
 4 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4e68fd45..b2e33fac 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -46,7 +46,23 @@ deploy-to-staging:
     name: "staging"
     url: "https://privatestorage-staging.com/"
   script:
-    - "./ci-tools/deploy-to-staging"
+    # Copy the deploy key from the environment to a file so we can actually
+    # tell ssh to use it.
+    - |
+      # The environment variable is configured with GitLab using Terraform so
+      # we can retain some bare minimum level of confidentiality.
+      echo "${PRIVATESTORAGEIO_STAGING_SSH_DEPLOY_KEY}" > "${PWD}"/deploy_key
+
+    # Update the deployment
+    - |
+      ./ci-tools/deploy-to-staging "${PWD}"/deploy_key ${name}
+
+    # Remove the key from the filesystem to less the chance of unintentional
+    # disclosure.  Overall our handling of this key is still not *particulary*
+    # safe or secure but that's why the key is only authorized to perform a
+    # single very specific operation.
+    - |
+      rm -v "${PWD}"/deploy_key
 
 deploy-to-production:
   stage: "deploy"
diff --git a/ci-tools/deploy-to-staging b/ci-tools/deploy-to-staging
index 47cdafa4..1bcaae6a 100644
--- a/ci-tools/deploy-to-staging
+++ b/ci-tools/deploy-to-staging
@@ -3,25 +3,42 @@
 
 set -euxo pipefail
 
-GRIDNAME="staging"
+DEPLOY_KEY=$1
+shift
+
+GRIDNAME=$1
+shift
 
 # Tell one node to update itself.
-update_yourself() {
+update_one_node() {
+    deploy_key=$1
+    shift
+
     node=$1
     shift
 
-    ssh -i deploy_key "${node}"
+    ssh -i "${deploy_key}" "deployment@${node}"
 }
 
-# Find the names of all hosts that belong to this grid.  This list includes
-# one extra string, "network", which is morph configuration stuff and we need
-# to filter out later.
-NODES=$(nix eval --json '(builtins.attrNames (import ./morph/${GRIDNAME}/grid.nix))')
+update_grid_nodes() {
+    deploy_key=$1
+    shift
 
-# Tell every system in the network to update itself.
-for node in ${NODES}; do
-    if [ "${node}" = "network" ]; then
-	continue
+    gridname=$1
+    shift
+
+    # Find the names of all hosts that belong to this grid.  This list includes
+    # one extra string, "network", which is morph configuration stuff and we need
+    # to filter out later.
+    nodes=$(nix eval --json '(builtins.attrNames (import ./morph/${gridname}/grid.nix))')
+
+    # Tell every system in the network to update itself.
+    for node in ${nodes}; do
+	if [ "${node}" = "network" ]; then
+	    continue
+	fi
+	update_one_node "${deploy_key}" "${node}"
     fi
-    update_yourself "${node}"
-fi
+}
+
+update_grid_nodes "${DEPLOY_KEY}" "${GRIDNAME}"
diff --git a/nixos/modules/deployment.nix b/nixos/modules/deployment.nix
index a12ff054..592d373f 100644
--- a/nixos/modules/deployment.nix
+++ b/nixos/modules/deployment.nix
@@ -1,17 +1,41 @@
 # A NixOS module which enables remotely-triggered deployment updates.
 { config, ... }:
 let
+  # A handy alias for our part of the configuration.
+  cfg = config.services.private-storage.deployment;
+
   # Compute an authorized_keys line that allows the holder of a certain key to
   # execute a certain command *only*.
-  restrictedKey = pubKey: command: "restrict,command=\"${command}\" ${pubKey}";
+  restrictedKey =
+    { authorizedKey, command, gridName }:
+    "restrict,command=\"${command} ${gridName}\" ${authorizedKey}";
 in {
   options = {
+    services.private-storage.deployment.authorizedKey = {
+      type = lib.types.str;
+      example = lib.literalExample ''
+        ssh-ed25519 AAAAC3N...
+      '';
+      description = ''
+        The SSH public key to authorize to trigger a deployment update.
+      '';
+    };
+    services.private-storage.deployment.gridName = {
+      type = lib.types.str;
+      example = lib.literalExample "staging";
+      description = ''
+        The name of the grid configuration to use to update this deployment.
+      '';
+    };
   };
 
   config = {
     users.users.deployment = {
       openssh.authorizedKeys.keys = [
-        restrictedKey cfg.deployKey ./update-deployment
+        (restrictedKey {
+          inherit (cfg) authorizedKey gridName;
+          command = ./update-deployment;
+        })
       ];
     };
   };
diff --git a/nixos/modules/update-deployment b/nixos/modules/update-deployment
index 7685423e..dd988031 100644
--- a/nixos/modules/update-deployment
+++ b/nixos/modules/update-deployment
@@ -3,8 +3,10 @@
 
 set -euxo pipefail
 
+GRIDNAME=$1
+shift
+
 CHECKOUT="/run/user/$(id --user)/PrivateStorageio"
-GRIDNAME="staging"
 REPO="https://whetstone.privatestorage.io/privatestorage/PrivateStorageio.git"
 
 if [ -e "${CHECKOUT}" ]; then
-- 
GitLab